UITableViewとは
iPod機能でもよくお世話になるリストの表示を受け持つ部分です。セクションにより区切られた中にセルという表示単位を持っています。上下にスクロールする機能を持っているので、表示しきれない分は下にスクロールさせると見ることが出来ます。上部にナビゲーションバーを組み合わせて、階層構造を持つデータの表示に使われることが多いです。システム側が用意するセルはこれまで1行のテキストとイメージを表示する基本機能をもつものだけでしたが、iPhone SDK 3.0になりセルの基本タイプが4種類に拡張されました。UITableViewの動作制御は基本的にそのコントローラーであるUITableViewControllerを通じて行います。ここではまず、Interface Builderを用いつつ設定を行う場合を説明してゆきます。実際にコードを書いてみる場合は、XcodeでNavigation-based Applicationを選んで新規にプロジェクトを作成してみてください。プロジェクト名は好きに付けて問題ないですが、一応標準名はTableTestとします。
Interface Builder側での基本設定
Interface Builderで行う基本設定項目はdataSourceとdelegateと、TableViewの外見の設定です。一般的にはdataSource、delegateともそのTableViewのコントローラーを指定します。TableViewの外見はInterface Builderから設定する場合は、Interface BuilderのメニューからToolsのAttributes Inspectorを選び、開いたウインドウの一番上にあるTable ViewのStyleを変更します。設定値はPlainとGroupedの2種類です。好きなほうを選んでください。
UITableViewControllerから行う基本設定
まずは設定のメソッドの説明ついでに全部手動で設定してみましょう。Xcodeで左側のツリー表示にあるClassesを展開してRootViewController.mファイルを開き、コードを下に挙げるものへと置き換えてみましょう。
ここで行う紹介する項目は以下のものです
- ナビゲーションバーにタイトルをつける
- セクションの数を決定する
- 各セクションのタイトルを決定する
- 各セクションのセルの数を決定する
- 各セルの表示内容を決定する
- セルが選択された時の動作を決定する
ナビゲーションバーにタイトルをつける
ナビゲーションバーがのっぺらぼうなのは味気ないので、タイトルをつけましょう。タイトルの付け方にはInterface Builde側で付ける方法と、Xcode側で付ける方法の2種類があります。多言語への対応を考えた場合にはXcode側で付けておいた方が良いので、ここではXcode側でタイトルを付けることにします。まずはViewDidLoadというメソッドが冒頭部分にあるはずなので、それを探してください。/*と*/で囲まれてコメント扱いにされているので、まずそれらを削除して、メソッドとして機能するようにします。削除したら、[super viewDidLoad];の下に、self.title=@"テーブル設定のテスト";と書いた行を足してください。下にコメントになっている行が2つあると思いますが、それらはそのままにしておいてください。この状態でビルドすると、ナビゲーションバーの中央に「テーブル設定のテスト」と表示されるのが確認できます。
セクションの数を決定する
そのTableViewがいくつのセクションを持つかを決定するのがnumberOfSectionsメソッドです。TableViewは少なくとも1個のセクションを持ちます。 numberOfSectionsメソッドの内容を以下のように書き換えてください。コメントは無くても構いません。
- (NSInteger)numberOfSections {
return 2; // セクションは2個とします
}
各セクションのタイトルを決定する
セクションの頭の部分に付けるタイトルを決定する部分がtitleForHeaderInSection:メソッドです。セクションにタイトルが不要なら@""(nil)を返させます。 常に不要ならこのメソッド自体を省略することも出来ます。セクションの番号は0から始まります。 下の例ではswitchを使ってsectionの値ごとに処理を分岐させています。 最後の行はビルド時に「返る値がないですよ」という警告が出ないように付けたダミーです。 またこの場合だとbreakの手前でメソッドが終了して値が返されるのでbreakは無くても問題ありませんが、一応付けてあります。 なお、警告はswitchでdefault:を用意しても出ます。これはテンプレートのままの状態では用意されていないので、自分でメソッドそのものを書き足す必要があります。
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
switch(section) {
case 0: // 1個目のセクションの場合
return @"セクションその1";
break;
case 1: // 2個目のセクションの場合
return @"セクションその2";
break;
}
return nil; //ビルド警告回避用
}
各セクションのセルの数を決定する
各セクションがいくつのセルを持つのかを決定するのがnumberOfRowsInSection:メソッドです。ここではifを使って分岐させてみました。この書き方の場合はsectionがどんな値であっても2個目のセクション用の部分が返るので、ビルド時に警告は出ません。
- (NSInteger)numberOfRowsInSection:(NSInteger)section {
if(section == 0) {
return 3; // 1個目のセクションのセルは3個とします
}
return 4; // 2個目のセクションのセルは4個とします
}
各セルの表示内容を決定する
セルに表示する内容を決定するのがcellForRowAtIndexPath:メソッドです。以下はiPhone SDK 3.0で、iPhone OS 3.0以上で動作するアプリケーションでの書き方です。動作対象がそれより前のバージョンの場合にはこのままでは動作しません。表示方法はいろいろなパターンがあるので、設定の仕方の例としてセクションごとに表示するテキストを別の方法で作ってみています。
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"] autorelease];
}
if(indexPath.section == 0) {
if(indexPath.row == 0) {
cell.textLabel.text = @"セクション0 行0";
} else if(indexPath.row == 1){
cell.textLabel.text = @"セクション0 行1";
} else {
cell.textLabel.text = @"セクション0 行2";
}
} else {
NSString *str = [[NSString alloc] initWithFormat:@"セクション%d 行%d",indexPath.section,indexPath.row];
cell.textLabel.text = str;
[str release];
}
return cell;
}
余談ですが、iPhone OS 2.2.1以下で動作するコードは以下のようになります。セルのalloc部分やテキストの設定部分が上と異なります。
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"] autorelease];
}
if(indexPath.section == 0) {
if(indexPath.row == 0) {
cell.text = @"セクション0 行0";
} else if(indexPath.row == 1){
cell.text = @"セクション0 行1";
} else {
cell.text = @"セクション0 行2";
}
} else {
NSString *str = [[NSString alloc] initWithFormat:@"セクション%d 行%d",indexPath.section,indexPath.row];
cell.text = str;
[str release];
}
return cell;
}
ここまでの部分でビルドすると、以下のようなテーブルが表示されます。左がPlainスタイル、右がGroupedスタイルの場合です。 indexPathのsectionやrowは0から始まるので、セクションのタイトルとはずれが生じることを理解しておいてください。 ここでは1番目が0であるということを意識してもらいやすいように、あえてずれを生じさせましたが、 自分のプログラムで整合性を持たせたい場合には、この例でのヘッダータイトルをその0からスタートさせるか、 セル側でindexPath.sectionに常に1を加えた値を表示させるかにあたる対応が必要になります。
セルが選択された時の動作を決定する
セルがタップされた時にどのような動作をするかを記述する部分がdidSelectRowAtIndexPath:メソッドです。 セルがタップされた時に行う動作としては、 何らかの変数に対して変更を行うか、下の階層へと移動するかのどちらかが考えられます。以下の例は変数を変更する場合の例です。 この例の場合は、RootViewController.hの@interfaceの中括弧内にNSInteger型のmyValueという変数の宣言を追加します。 「NSInteger myValue;」と書いた行を追加すればOKです。選んだセルによりmyValueの値が変化し、それがコンソールへと出力されます。この出力値も実用とはかけはなれたような状態になっていますので、自分のプログラムで応用する場合は工夫をしてみてください。
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES]; // 選択状態の解除をします。
if(indexPath.section == 0) { // 1個目のセクションです。
if(indexPath.row == 0) {
myValue = -3;
} else if(indexPath.row == 1) {
myValue = -2;
} else {
myValue = -1;
}
} else { // 2個目のセクションです。
myValue = indexPath.row; // 行の値をmyValueに代入しています。
}
NSLog(@"myValue:%d",myValue); // myValueの値をコンソールへ出力します。
}
以下の例は下の階層への移動を行う場合の例です。iPhone SDK 3.0の場合で説明します。
1.まずClassesにファイルを追加します。Classesを選んだ状態でメニュのファイルから新規ファイルを選びます。開いたウインドウの左上の部分からiPhone OSのCocoa Touch Classesを選び、右上の部分からはObjective-C Classesを選びます。中央付近のSubclass ofの右側からUITableViewControllerを選んで次へを押します。ファイル名はAnotherViewControllerにしてください。
2.次にResoucesを選択した状態でメニューのファイルから新規ファイルを選び、iPhone OSのUser InterfaceからView XIBを選んでください。ファイル名はAnotherViewとします。作られたxibファイルをダブルクリックしてInterface Builderを起動します。
3.Interface Builderが起動したら、Viewを選んでDeleteキーを押し、Viewを削除します。LibraryのCocoa Touchの下の階層のData ViewsにあるTable ViewをさきほどViewがあった位置にドラッグします。追加されたTable Viewの上にマウスカーソルを置き、Ctrlキーを押しながらマウスボタンを押します(Windows用の2ボタンマウスなら何もボタンを押さずに右クリックでも同じ動作をします)。dataSourceとdelegateをFile's Ownerへ紐付けします。
4.File's Ownerを選び、メニューのToolsからIdentity Inspectorを選びます。表示されたAnother View Controller Identityの中央付近にClass Outletsという項目があるので、下の+ボタンを押してOutletを追加します。OutletはtableView、TypeはUITableViewとします。
5.File's Ownerの上にマウスカーソルを置き、Ctrlキーを押しながらマウスボタンを押します。OutletのtableViewとviewを3.で追加したTable Viewと紐付けします。
6.変更を保存したらXcodeに戻り、RootViewController.mの冒頭に「#import "AnotherViewController.h"」と書いた行を足します。
7.didSelectRowAtIndexPathメソッドを以下のように書き換えます。2、4、5行目はテンプレートで作られたコメントの//を消してそのまま流用できます。
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES]; // 選択状態の解除をします。
AnotherViewController *anotherViewController =
[[AnotherViewController alloc] initWithNibName:@"AnotherView" bundle:nil];
anotherViewController.title = @"下の階層です";
[self.navigationController pushViewController:anotherViewController animated:YES];
[anotherViewController release];
}
実行してセルをタップした状態が下のスクリーンショットです。左がPlainスタイル、右がGroupedスタイルです。 ナビゲーションバーの左側のボタンを押せば、上の階層に戻ります。 Groupedスタイルの場合には、1個もセルが無いと背景しか表示されないことがわかります。 AnotherViewControllerにも上で行ったようなセルの設定を行えば、セルに文字を表示させることができます。
前へ次へ