iOS (iPhone/iPad) アプリ開発でステッパー (UIStepper) をテーブルのセルに組みこむ

UITableView のセルに UIStepper を組みこんで、Cell の数値を増減させることを考える。ステッパー自体はさして複雑なところはないんだけど、UITableViewCell を再利用するところで多少工夫がいったので、個人的にメモ。というか、ほぼソースのみ。CustomTableController クラスは UITableViewController クラスのサブクラスとして作っておく。ベースのプロジェクトは、Xcode で empty application を選んで作成する。

下のソースでは stepper を subview に組みこんでるけど、contentView に設定してやるほうがスマートぽい。また for イタレータで探すより、insertSubView:atIndex: で追加して index で探すほうがよさげ。

  • AppDelegate.h

特筆することはなし。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    
    CustomTableController *table = [[CustomTableController alloc] initWithStyle: UITableViewStylePlain];
    [self.window setRootViewController: table ];
    
    [self.window makeKeyAndVisible];
    return YES;
}
  • CustomTableController.m

変更の必要なメソッドだけを抜粋。

static int array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 16; // array の要素の数
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    UIStepper *step;
    
    if (cell == nil) {
        
        step = [[UIStepper alloc] init];
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
        
        // ステッパーの最小サイズは 94 x 27 ぽい?
        step.frame = CGRectMake(320-94-20, 8, 94, 27 );
        // ステッパーが押されたときに pushStepper: メッソドを呼びだすように設定
        [step addTarget:self action:@selector(pushStepper:) 
              forControlEvents: UIControlEventTouchUpInside ];
        // cell の subview に設定
        [cell addSubview:step];
    }else{

        // dequeueReusableCellWithIdentifier で再利用するときは addSubview してはいけない
        // subview の中から stepper を探す
        for ( id v in [cell subviews] )
        {
            if ( [v class] == [UIStepper class] )
            {
                step = v;
                break;
            }
        }
    }
    
    // array の値を使って現在値を設定
    step.value = array[indexPath.row];
    
    step.minimumValue = 0;
    step.maximumValue = 20;
    step.stepValue = 1; // 刻み値は小数も設定可能
    step.tag = indexPath.row; // tag にstepper の番号を設定しておく

    // 現在値を cell のテキストに設定
    [cell.textLabel setText: [NSString stringWithFormat:@"%d", array[indexPath.row]]];
    
    return cell;
}

// stepper が押されたときに呼ばれる
- (void)pushStepper:(UIStepper*)stepper
{
    // array の値を stepper の値にあわせる
    array[stepper.tag] = stepper.value;
    
    // テーブルの項目を強制的に更新
    [self.tableView reloadData];
}