StoryBoard等ではUITableViewではコンテンツのタイプで”Dynamic Prototypes”と”Static Cells”が選べるようになっています(iOS5から)

NewImage

“Static Cells”はiOS5から使うことができ、名前の通りInterface builder(GUI)上でTableViewの見た目を作ることができます。
そのため、複数の入力UIを併せ持つような 設定画面 などでとても効果を発揮します。

NewImage

設定の見た目をGUIで作って、後はUIViewControllerと同じようにoutletを結んで処理を書くだけで済むようになります。
今までの”Dynamic Prototypes”の方式ではコードで X section の Y rowは何を表示する等といったdataSourceの定義が必要になり、
見た目以上にコード量が増えてしまうので、”Static Cells” で十分な場合は”Static Cells”を使ったほうが圧倒的に楽になります。

逆に、”Static Cells”で済まない場合というのは、staticではないということなので、セルの増減が入るようなTableViewの場合は、
“Static Cells”では行う事ができません(やる方法があったら知りたい)

設定画面のように入力UIが複数あって、なおかつセルを動的に追加したりするようなUIが必要な場合は、
“Dynamic Prototypes”を使って行わないといけません。

例えば、以下のように”Static Cells”で作れたら楽な部分と動的にセルの追加が必要なものが混ざったデザインを考えみます。

実際に”Dynamic Prototypes”で作ったものは下記にあります。

DynamicUI

このUIを”Dynamic Prototypes”で以下に楽に作るかというのが今回の本題です。

Dynamic Prototypesでできる事

Dynamic Prototypesの場合でも実はInterface builder上でセルの見た目を作成することができます。

ただし、この”Dynamic Prototypes”上で追加したUITableViewCellは、その配置のまま表示されてる訳ではなく、
UITableViewCellにidentifierを振り、それをコード上で取得して表示するためのカスタムセルを作っているのと同じです。

Static cell xcodeproj  MainStoryboard storyboard

以前、シンプルなカスタムセルの作り方とセル内のボタンへのイベント設定方法 | Technology-Gymで紹介したカスタムセルの作り方では、
xibに単独の UITableViewCell を作ってそれをUITableViewControllerでregisterNib:を使い読み込んで使用していました。

SimpleCustomCell xcodeproj  SmartCell xib

今回の、”Dynamic Prototypes”上で作るカスタムセルはregisterNib:が既にされている状態のような感じなので、
後は [tableView dequeueReusableCellWithIdentifier:cellIdentifier];という感じで呼び出せば扱えるようになっています。

“Dynamic Prototypes”上のカスタムセルと別ファイルとして作るカスタムセルの使い分けとしては、
別ファイルとして作るカスタムセルの方が汎用性は高いので色んなクラスで利用できますが、セルごとにバラバラで保存されているのでまとまりがないです。
(一つのカスタムセルを並べてリスト表示するようなUIにはコチラのほうが汎用性が出る気がします)
逆に “Dynamic Prototypes”上のカスタムセル は その定義してるUITableViewController以外では使わないので、
一箇所で複数のカスタムセルを管理できるので利点です。

今回は”Dynamic Prototypes”上のカスタムセルを作っていきます。
目的のUIではセルの種類は4種類となっているので、以下のように4つの UITableViewCell を作って、それぞれにidentifierを付けていきます。

Static cell xcodeproj  MainStoryboard storyboard 1

後は、[tableView dequeueReusableCellWithIdentifier:@"kCellName"]; というような感じでカスタムセルのインスタンスが取得できますが、
identifierを文字列で指定するのは避けたいと思います。

そこでUser Defined Runtime Attributesを利用します。(iOS5以上から利用可能)
User Defined Runtime AttributesはInterface builder上から、クラスのプロパティに特定の値を実行時に代入する機能です。

今回の例では先にTableViewControllerのクラスのプロパティを宣言しておいて、user defined runtime attributes経由でそこに
それぞれのカスタムセルのidentifierを代入するようにします。


@interface MyTableViewController : UITableViewController  {

}
// ...
#pragma mark - user defined runtime attributes
@property(nonatomic, strong) NSString *idNameCell;
@property(nonatomic, strong) NSString *idTimeCell;
@property(nonatomic, strong) NSString *idAddCell;
@property(nonatomic, strong) NSString *idSwitchCell;
// ...
@end

user defined runtime attributesは以下のように、KeyPathにプロパティへのKeyPath、Valueにカスタムセルのindetifierを入れておきます。
こうすると、実行時にはself.idNameCellは@”kCellName”という値が入るようになるので、コード上に文字列を書く必要はなくなります。

Static cell xcodeproj  MainStoryboard storyboard 2

これで”Dynamic Prototypes”上のカスタムセルの扱いを少しマシにできました。

次にセルの配置について考えてみます。

“Static Cells”では、セルの配置セクションの構成などもInterface builder上で配置できるので何も考えなくても見た目を作成できます。
しかし、”Dynamic Prototypes”では<UITableViewDataSource>でセルの配置を考えたりするため、コードで配置を定義しないといけません。

Objective-Cのliteralを使って、配置だけ配列と辞書を使って作っていきます。
今回は次のようなイメージで、sectionが配列で、それぞれのセルが辞書という感じにして、
辞書のkCellIdentifierの値がカスタムセルの種類を指定するという感じにしました。


    @[
        // section
        @[
            // cell
            @{
                kCellIdentifier : @"cell id"
            },
        ],
        // section
        @[
            // cell
            @{
                kCellIdentifier : @"cell id",
            },
            // cell
            @{
                kCellIdentifier : @"cell id",
            },
        ],
    ];

実際には次のように、dataSourceを更新するメソッドを作って、
毎回固定(static)な部分と、メソッドを呼び出して動的にsectionを作る部分を混ぜたdataSourceを作ります。


- (void)updateDataSource {
    self.dataSource = [[NSMutableArray alloc] initWithArray:@[
    // static
    @[
        @{
        kCellIdentifier: self.idNameCell
        }
    ],
    // dynamic
    [self timeStampAddDataSource],
    // static
    @[
        @{
        kCellIdentifier: self.idSwitchCell
        }
    ]
    ]];
}

timeStampAddDataSourceメソッドは、タイムスタンプのカスタムセル(self.idTimeCell)は動的に追加されるので、
タイムスタンプのカスタムセルの配列の末尾に、タイムスタンプを追加するためのセル(self.idAddCell)を追加した配列を返すメソッドです。

NewImage


- (NSArray *)timeStampAddDataSource {
    NSArray *array = [self.timeStampDataSource copy];
    return [array arrayByAddingObject:@{
    kCellIdentifier:self.idAddCell
    }];
}

[self updateDataSource];すれば、配置の情報を持ったdataSourceが作られるので、
後はそのdataSourceに従って<UITableViewDataSource>を実装していくだけになります。

dataSourceと作られるUIの対応を見ると以下のようなイメージ

Skitched 20121113 175841

この辺の実装についてはソースなどを参照するといいかと思います。

これで、以下の要素を使って”Static Cells”で作る時程は楽では無いですが、動的にセルの増減するTableViewをある程度扱い易く作れるようになると思います。
(配置のdataSourceとかをもう少し上手くやりたいですが…)

  • Dynamic Prototypes
  • user defined runtime attributes
  • Custom Cell

Post Navigation