UIPickerViewのマルチコンポーネント

2010/05/29

外ぶらっとしに行って、ついでにiPadを買いそうになりましたw Wifiモデルでも並ばなきゃ買えなかったので、諦めましたが。

さて、UIPickerViewの続き。 今度は2つのコンポーネントを表示。 iPhone

まずコンスタンスとして2つのコンポーネントの番号を設定しておく

#define kPlayerComponent 0
#define kPostionComponent 1

次に、データ配列を作成

- (void)viewDidLoad {
    NSArray *playerArray = [[NSArray alloc] initWithObjects:
                            @"荒木", @"大島", @"森野", @"ブランコ",
                            @"和田", @"井端", @"セサル", @"谷繁",nil];
    self.players = playerArray;
    [playerArray release];
    
    NSArray *positionArray = [[NSArray alloc] initWithObjects:
                            @"ピッチャー", @"キャッチャー", @"ファースト", @"セカンド",
                            @"サード", @"ショート", @"レフト", @"センター", @"ライト",nil];
    self.positions = positionArray;
    [positionArray release];
    
}

ここまではほぼ前と同じ。 UIPickerViewのデータは、この書籍では条件分岐で返してます。

#pragma mark Picker Data source method
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    return 2;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView 
    numberOfRowsInComponent:(NSInteger)component {
    if (component == kPlayerComponent) {
        return [self.players count];
    } else if (component == kPostionComponent) {
        return [self.positions count];
    }
       return 0;
}
#pragma mark Picker Delegate method
- (NSString *)pickerView:(UIPickerView *)pickerView
             titleForRow:(NSInteger)row
            forComponent:(NSInteger)component {
    if (component == kPlayerComponent) {
        return [self.players objectAtIndex:row];
    } else if (component == kPostionComponent) {
        return [self.positions objectAtIndex:row];
    }
       return 0;
}

うーん、汎用的にするには連想配列にすべきですね。 次は、NSDictionaryを利用した場合。 iPhone

その前に参考書籍には、アメリカのZIPコードデータ「statedictionary.plist」が必要。 海外サイトにサンプルソースがあるらしいので検索。

www.iphonedevbook.com

ここのフォーラムにあるのだが、Regist & Loginしないとダウンロードできないです(^^;) さらにソースの場所もわかりにくいのでメモ・・・以下のフォーラムにあります。

Beginning iPhone Development ‹ Hey! Over here! Here's the source code to the book!!!

ダウンロードしたら「Resources」に「statedictionary.plist」を入れておく。 今回のサンプルは、基本は変わらないが、statedictionary.plistを読み込んでNSDictionaryとして扱うのがポイント。

- (void)viewDidLoad {
    NSBundle *bundle = [NSBundle mainBundle];
    NSString *plistPath = [bundle 
                           pathForResource:@"statedictionary" 
                           ofType:@"plist"
                           ];
    
    NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
    self.stateZips = dictionary;
    [dictionary release];
    
    NSArray *components = [self.stateZips allKeys];
    NSArray *sorted = [components sortedArrayUsingSelector:@selector(compare:)];
    self.states = sorted;
    
    NSString *selectedState = [self.states objectAtIndex:0];
    NSArray *array = [self.stateZips objectForKey:selectedState];
    self.zips = array;
    
    [super viewDidLoad];
}

外部ファイルの読み込みは、Bundleを用意して

NSBundle *bundle = [NSBundle mainBundle];

Resourcesからのファイルパスを生成して、

NSString *plistPath = [bundle pathForResource:@"statedictionary" ofType:@"plist"];

NSDictionaryに格納する。

NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];

NSArray、NSDictionaryの特記として

・allKeys ・objectForKey ・sortedArrayUsingSelector

@selector(compare:)の「compare」はNSComparisonResultのメソッド。 大文字小文字を区別しない「caseInsensitiveCompare」もある。

次に、ピッカーが選択された時の動作

-(void)pickerView:(UIPickerView *)pickerView 
            didSelectRow:(NSInteger)row
            inComponent:(NSInteger)component {
    if (component == kStateComponent) {
        NSString *selectedState = [self.states objectAtIndex:row];
        NSArray *array = [stateZips objectForKey:selectedState];
        self.zips = array;
        [picker selectRow:0 inComponent:kZipComponent animated:YES];
        [picker reloadComponent:kZipComponent];
    }
}

didSelectRow inComponentメソッドを記述してやるだけでOK。 条件がZipコンポーネントでなく、Stateコンポーネントなのが、思考的にややこしい。 引数のcomponentは動かしたコンポーネント番号ではなく、

全コンポーネントをチェック時のコンポーネント番号

らしい。 つまりstateデータを更新したければ、stateのコンポーネント番号でOK Eventのプログラム思考でいくと、何か変な感じですがw