読者です 読者をやめる 読者になる 読者になる

ニペブ - iPhone / iOSアプリ開発

iPhone / iOS アプリ開発方法と技術情報、入門レベルの初心者向けの記事を書いています。

(iOS/iPhoneアプリ開発) Pickerを使い 年 と 月 だけのPickerを作成

完成イメージ

iPhoneではDatePickerとしてデフォルトで4種類ほどの表示がありますが、年と月だけが表示されるPickerが必要になっため作成しました。

完成イメージは次の通りです。
「西暦(年)と月を表示するラベル」と「西暦(年)と月を選択するPicker」という簡単な2つの部品でできています。
f:id:nipe880324:20131201201846p:plain:w320

環境

StoryBoardの作成

まずは、次のようにStoryBoardを作成します。
f:id:nipe880324:20131201201829p:plain

  1. 年と月を表示するラベル(Label)を追加
  2. 年と月を選択するPicker(Picker View)を追加
  3. StoryBoardとViewController.hの2つのビューにし、「Ctrl + ドラッグ」を使って、上記の2つの部品をViewController.hに追加

ViewController.hに次のような記述が記載されます。

@property (weak, nonatomic) IBOutlet UILabel *dateLabel;
@property (weak, nonatomic) IBOutlet UIPickerView *pickerView;

ViewController.hの作成

次に、ViewController.h を作成します。
詳細はコメントを確認してください。

#import <UIKit/UIKit.h>

@interface PickerViewController : UIViewController
<UIPickerViewDelegate>  // PickerViewのデータやタップ時のイベントのため
{
    NSMutableArray *years, *months;    // PickerViewの年と月のデータ保持用
}
// PickerViewで設定されている日付の表示用
@property (weak, nonatomic) IBOutlet UILabel *dateLabel;
// Pickerview用
@property (weak, nonatomic) IBOutlet UIPickerView *pickerView;
@end

ViewController.mの作成

次に、ViewController.m を作成します。
PickerViewでは、列のことをcomponent、行のことをrowと呼んでいます。

PickerViewの表示のためには次のデリゲートを実装する必要があります。

// 列数を返す
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
// 各列に対する、行数を返す
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;
// 列×行に対応する文字列を返す
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component;

また、PickerViewのイベントを処理するためには次のデリゲートを実装する必要があります。

// PickerViewの操作が行われたときに呼ばれる
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row  inComponent:(NSInteger)component;

実際のソースコードです。
細かくコメントを記載してますのでそれを見れば大体分かると思います。

#define FIRST_YEAR 1970     // PickerViewの最初の年
#define LAST_YEAR  2030     // Pickerviewの最後の年

#import "PickerViewController.h"

@interface PickerViewController ()

@end

@implementation PickerViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 現在の日付を取得
    NSDate *today = [NSDate date];

    // 現在の日付(NSDate)から年と月をintで取得
    NSCalendar* calendar = [NSCalendar currentCalendar];
    NSDateComponents* components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit fromDate:today];
    int todayYear  = components.year;   // 現在の年を取得
    int todayMonth = components.month;  // 現在の月を取得
    
    // ラベルに現在の日付を表示
    self.dateLabel.text = [NSString stringWithFormat:@"西暦%d%d月", todayYear, todayMonth];
    
    // Pickerviewにデリゲートを設定
    self.pickerView.delegate = self;

    // -------------------------------------------
    // PickerViewに表示させるデータの作成
    // -------------------------------------------
    // PickerViewに年部分に表示させる年データの作成 (1970, 1971, ..., 2030)
    years = [[NSMutableArray alloc] initWithCapacity:(LAST_YEAR-FIRST_YEAR)];
    for (int i = FIRST_YEAR; i <= LAST_YEAR; i++) {
        [years addObject:[NSString stringWithFormat:@"%d", i]];
    }
    // PickerViewの月部分に表示させる月データの作成 (1, 2, ..., 12)
    months = [[NSMutableArray alloc] initWithCapacity:12];
    for (int i = 1; i <= 12; i++) {
        [months addObject:[NSString stringWithFormat:@"%d", i]];
    }
    
    // -------------------------------------------
    // PickerViewに初期の選択値として、現在の日付を設定
    // -------------------------------------------
    // PickerViewの列数を計算する
    // 列数(row)は0から始まるので注意。例えば、1970年を指定したかったらrowは0, 1971ならrowは1となる
    int rowOfTodayYear  = todayYear  - FIRST_YEAR;    // 年の列数を計算
    int rowOfTodayMonth = todayMonth - 1;             // 月の列数を計算
    // PickerViewの初期の選択値を設定
    // componentが行番号、selectRowが列番号
    [self.pickerView selectRow:rowOfTodayYear inComponent:0 animated:YES];  // 年を選択
    [self.pickerView selectRow:rowOfTodayMonth inComponent:1 animated:YES]; // 月を選択
}

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

# pragma mark UIPIkerView's Delegate
// 列(component)の数を返す
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    // 年と月を表示するので2列を指定
    return 2;
}

// 列(component)に対する、行(row)の数を返す
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    switch (component) {
        case 0: // 年(1列目)の場合(配列と同じように0から始まる)
            return [years count];   // 年のデータ数を返す
        case 1: // 月(2列目)の場合
            return [months count];  // 月のデータ数を返す
    }
    return 0;
}

// 列(component)と行(row)に対応する文字列を返す
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    switch (component) {
        case 0: // 年(1列目)の場合(配列と同じように0から始まる)
            return [years objectAtIndex:row];   // 年のデータの列に対応した文字列を返す
        case 1: // 月(2列目)の場合
            return [months objectAtIndex:row];  // 月のデータの列に対応した文字列を返す
    }
    return nil;
}


// PickerViewの操作が行われたときに呼ばれる
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row  inComponent:(NSInteger)component {
    
    // PickerViewの選択されている年と月の列番号を取得
    int rowOfYear  = (int)[pickerView selectedRowInComponent:0]; // 年を取得
    int rowOfMonth = (int)[pickerView selectedRowInComponent:1];          // 月を取得
    
    // ラベルに現在の日付を表示
    self.dateLabel.text = [NSString stringWithFormat:@"西暦%@%@月",
                           [years objectAtIndex:rowOfYear], [months objectAtIndex:rowOfMonth]];
}

@end


PickerなどのUIKitに関するサンプルのソースコードGithubに置いてあります。よろしければ、覗いてみてください。
yanagi0324/test-uikit · GitHub

参考情報

分かりづらい箇所やご質問などありましたら、 コメントやメールアドレスにご連絡いただけると嬉しいです。