2013年8月26日月曜日

ループする(している様に見せる) PickerView の作り方

今頃のアプリの項目選択では、余り使われなくなった PickerView。
時代に反しながら、それでも利便性がある所があるため使い方を学習した。

通常に実装しただけでは、ループが施される処理にはならず、ドラムの先頭には空白が表示される。









↑こんなかんじ

これをループ形式にする。








↑こんなかんじに

ちなみに画像が違うのは、Blog を書いている PC は開発機ではないため、実際の画像が取得できないので、イメージを取ってきているから(実装内容はポイント押さえてるからご勘弁を)。

要するに、数値で行けば、0 ~ 9 をループさせると言うようにする。

この実装をどのようにするかというと、プロパティ等ではなくカラクリがある。
実際にはこれループをしているわけではない。
ループさせたい番号を一定数繰り返している長~いビューを見せているだけなのである。

最初は、「そんなバカなプロパティあるんだろ?」と思っていたが、当然無くまたどのソースをみてもこの方法を採用している(当たり前か)。

当然ただただ長いビューを表示させているので、先頭と終端があり、何も考えずに表示すると最初に載せている通り先頭が空白の状態が表示される。
これでは、ループに見えないので、最初に表示する際には、中間地点の先頭(この場合は 0)を表示するようにする。

なので、ループに見えるようなPickerViewの場合、頑張って先頭もしくは終点までクルクル回すと先頭(終点)が表示される。

また、終点近くまでクルクル回してそれで終わりとすると、次回のクルクルの時に直ぐに終わりが来てしまうとまずいので、選択が確定したら、中心部近くへ移動させる処理も入れないと行けない。

これらを実装した内容は以下の通りになる。
今回のソースは、時・分をループさせるような物を作成している。
(上にも書いたけど画像と実装内容が微妙にずれていて申し訳ない)

ポイントは上に書いたから良いか。。。
    #import <UIKit/UIKit.h>

    @interface ViewController : UIViewController<UIPickerViewDelegate, UIPickerViewDataSource> {
        NSTimer *timer_1sec;
    }

    @property (strong, nonatomic) NSMutableArray *hours;
    @property (strong, nonatomic) NSMutableArray *minutes;

    @property (weak, nonatomic) IBOutlet UILabel *timer_count;
    @property (weak, nonatomic) IBOutlet UIPickerView *pvTime;

    @end
    #import "ViewController.h"

    #define MAX_HOURS 24
    #define MAX_MINUTES 60

    #define LOOP_COUNT 6

    @interface ViewController ()

    @end

    @implementation ViewController

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.

        _pvTime.delegate = self;
        
        // データ準備
        // 時
        _hours = [NSMutableArray arrayWithCapacity:MAX_HOURS * LOOP_COUNT];
        for(int i=0; i<LOOP_COUNT; i++) {
            for(int j=0; j<MAX_HOURS; j++) {
                [_hours addObject:[NSString stringWithFormat:@"%02d",j]];
            }
        }
        
        // 分
        _minutes = [NSMutableArray arrayWithCapacity:MAX_MINUTES * LOOP_COUNT];
        for(int i=0; i<LOOP_COUNT; i++) {
            for(int j=0; j<MAX_MINUTES; j++) {
                [_minutes addObject:[NSString stringWithFormat:@"%02d",j]];
            }
        }
        
        // 中央に移動(先頭番号)をセット
        [_pvTime selectRow:MAX_HOURS * (LOOP_COUNT * 0.5f)
               inComponent:0
                  animated:NO];
        [_pvTime selectRow:MAX_MINUTES * (LOOP_COUNT * 0.5f)
               inComponent:1
                  animated:NO];

    }

    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }

    // ドラムの数(本数)を指定
    - (NSInteger) numberOfComponentsInPickerView:(UIPickerView *)pickerView {

        return 2;

    }

    // 各ドラムのセル数をセット
    - (NSInteger) pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
        
        NSInteger count = 0;
        
        switch (component) {
            case 0 :
                count = [_hours count];
                break;
            case 1 :
                count = [_minutes count];
                break;
            default:
                break;
        }

        return count;
        
    }

    // ドラムのセルに表示するタイトルをセット
    - (NSString *)pickerView:(UIPickerView *)pickerView
                 titleForRow:(NSInteger)row forComponent:(NSInteger)component {
        
        NSString *title;
        switch (component) {
            case 0 :
                title = [_hours objectAtIndex:row];
                break;
            case 1 :
                title = [_minutes objectAtIndex:row];
                break;
            default:
                break;
        }
        
        return title;
        
    }

    // 選択後に呼ばれる
    - (void)pickerView:(UIPickerView *)pickerView 
          didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
        
        // 時
        NSInteger index = [_pvTime selectedRowInComponent:0];
        // 中央付近に戻す
        [_pvTime selectRow:(index % MAX_HOURS) + (MAX_HOURS * (LOOP_COUNT * 0.5f))
               inComponent:0 animated:NO];
        // 値の確認
        NSLog(@"%d, %@", index, _hours[index]);

        // 分
        index = [_pvTime selectedRowInComponent:1];
        // 中央付近に戻す
        [_pvTime selectRow:(index % MAX_MINUTES) + (MAX_MINUTES * (LOOP_COUNT * 0.5f))
               inComponent:1 animated:NO];
        // 値の確認
        NSLog(@"%d、%@", index, _minutes[index]);
        
    }

    @end

0 件のコメント:

コメントを投稿