☆Cocoa Touch UIKit勉強(4)
UITableView
UITableViewは、テーブル形式の画面表示や編集を制御するビューである。
UIKitが提供するテーブルビューは、小さな画面ゆえに縦1列に限っている。
多くの制御が出来るため、プロパティーやメソッドが非常に多い。
Table View Programming Guide for iOSも参照のこと。
テーブルビューは0以上の「セクション」からなる。各セクションはそれぞれ行を持っている。
セクションに分けることを「グループ化」という。
各セクションには上にヘッダを、下にフッタを付けることが出来る。
| 単一(plane)形式(例1) | 単一形式(例2) | 単一形式(例3) | グループ化=セクションがある形式 |
 |  |  |  |
UITableView
| メソッド名 | 動作 |
| -(id)initWithFrame:(CGRect)frame style:(UITableViewStyle)style | 形を指定してテーブルビューオブジェクトを初期化する |
| -(NSInteger)numberOfRowsInSection:(NSInteger)section | 指定セクションの行数を返す |
| -(NSInteger)numberOfSections | レシーバー内のセクション数を返す |
| -(NSIndexPath *)indexPathForCell:(UITableViewCell *)cell | 与えられたテーブルビューセルの行とセクションをインデックスパスで返す |
| -(NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point | タッチポイントで与えられた行とセクションをインデックスパスで返す |
| -(NSIndexPath *)indexPathForSelectedRow | 選択された行の行とセクションをインデックスパスで返す |
| -(NSArray *)indexPathsForRowsInRect:(CGRect)rect | 与えられた長方形で囲まれる行の示すインデックスパスの配列を返す |
| -(NSArray *)indexPathsForVisibleRows | レシーバー内で見えている行のインデックスパスの配列を返す |
| -(void)reloadData | 行とセクションのデータをリロードする |
-(void)reloadRowsAtIndexPaths:(NSArray *)indexPaths
withRowAnimation:(UITableViewRowAnimation)animation | アニメーション効果を使って指定行をリロードする
|
| -(void)reloadSectionIndexTitles | テーブルビュー右のインデックスバー内のアイテムをリロードする |
| -(void)reloadSections:(NSIndexSet *)sections
withRowAnimation:(UITableViewRowAnimation)animation | アニメーション効果を使って指定セクションをリロードする |
| -(void)scrollToNearestSelectedRowAtScrollPosition:(UITableViewScrollPosition)scrollPosition
animated:(BOOL)animated | 選ばれた行が指定された位置の最も近くにあるように、テーブルビューをスクロールする
UITableViewScrollPosition(enum値)
| UITableViewScrollPositionNone | テーブルビューは、最小限の移動で指定行をスクロールする(デフォルト)
列がすでに完全に見えるているなら、スクロールは起こらない |
| UITableViewScrollPositionTop | 見えるテーブルビューの先頭に、指定行をスクロールする |
| UITableViewScrollPositionMiddle | 見えるテーブルビューの中央に、指定行をスクロールする |
| UITableViewScrollPositionBottom | 見えるテーブルビューの最後に、指定行をスクロールする |
|
| -(void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath
atScrollPosition:(UITableViewScrollPosition)scrollPosition
animated:(BOOL)animated | インデックスパスによって確認される行がスクリーンで特定の場所にくるまでレシーバーをスクロールする
|
| -(void)selectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated
scrollPosition:(UITableViewScrollPosition)scrollPosition | インデックスパスで指定される行を選択する(スクロール付き)
|
| -(void)deselectRowAtIndexPath:(NSIndexPath *)indexPath
animated:(BOOL)animated | インデックスパスで指定される行を非選択にする
|
| -(NSArray *)visibleCells | レシーバーで表示可能なテーブルセルを返す |
| -(UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath | 指定されたインデックスパスのセルを返す |
| -(void)setEditing:(BOOL)editing animated:(BOOL)animate | 編集モードをON/OFFする |
| -(void)endUpdates | 編集を終了する |
| -(void)beginUpdates | 挿入、削除、選択、列とセクションの削除によるメソッド呼び出しを開始する |
-(void)deleteRowsAtIndexPaths:(NSArray *)indexPaths
withRowAnimation:(UITableViewRowAnimation)animation | インデックスパス配列中から指定行を消す
|
| -(void)deleteSections:(NSIndexSet *)sections
withRowAnimation:(UITableViewRowAnimation)animation | 1つ以上のセクションをレシーバーから削除する
|
-(void)insertRowsAtIndexPaths:(NSArray *)indexPaths
| インデックスパスで指定される位置に行を挿入する
withRowAnimation:(UITableViewRowAnimation)animation
UITableViewRowAnimation(enum値)
| UITableViewRowAnimationFade | 挿入されたか削除された行は、テーブルビューに、フェードインまたはフェードアウトされる |
| UITableViewRowAnimationRight | 挿入されたか削除された行は右から入る・右へ消える |
| UITableViewRowAnimationLeft | 同、左 |
| UITableViewRowAnimationTop | 同、先頭 |
| UITableViewRowAnimationBottom | 同、最後 |
| UITableViewRowAnimationNone | アニメーションしない |
| UITableViewRowAnimationMiddle | セルの中央に消える、中央から広がるように現れる |
|
-(void)insertSections:(NSIndexSet *)sections
withRowAnimation:(UITableViewRowAnimation)animation | セクションを追加する
|
| プロパティ名 | 属性 | 内容 |
| id <UITableViewDataSource> dataSource | S | データソースを設定する |
| id <UITableViewDelegate> delegate | S | デリゲートを設定する |
| BOOL editing | G=isEditing | 編集モードにするかどうか |
| UITableViewStyle style | R |
UITableViewStyle(enum値)
| UITableViewStylePlain | 単一(plane)形式 |
| UITableViewStyleGrouped | グループ化形式 |
|
| UIView *tableFooterView | T | フッター指定 |
| UIView *tableHeaderView | T | ヘッダー指定 |
| UIView *backgroundView | WT | 背景のビュー |
| NSInteger sectionIndexMinimumDisplayRowCount | | 索引リストをテーブルの右端に表示するためのテーブル行数 |
| BOOL allowsSelection | | ユーザーがセルを選択できるかどうか |
| BOOL allowsSelectionDuringEditing | | 編集モードにいるとき、セルを選択できるかどうか |
| CGFloat rowHeight | | 行の高さ |
| CGFloat sectionFooterHeight | | section footersの高さ |
| CGFloat sectionHeaderHeight | | section headerの高さ |
| UIColor *separatorColor | T | 行区切り線の色 |
| UITableViewCellSeparatorStyle separatorStyle | | セパレーターとして使うセルの形状
UITableViewCellSeparatorStyle(enum値)
| UITableViewCellSeparatorStyleNone | セパレーターセルには、異なったスタイルがない |
| UITableViewCellSeparatorStyleSingleLine | 幅分の1重横線(デフォルト) |
| UITableViewCellSeparatorStyleSingleLineEtched | 幅分のエッチングされた(刻み込まれた)2重横線
グループ化されたテーブルビューでのみサポートされる |
|
テーブルビューのデータは
UITableViewDataSourceで与える。
| メソッド名 | 動作 |
| -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView | セクション数 |
| -(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView | テーブルビューの文字列群 |
| -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath | 指定位置に入れるセル(必須) |
-(BOOL)tableView:(UITableView *)tableView
| canEditRowAtIndexPath:(NSIndexPath *)indexPath |
| canMoveRowAtIndexPath:(NSIndexPath *)indexPath |
|
| 与えられた行が編集可能かどうか |
| 与えられた行が他の位置に移動可能かどうか |
|
-(void)tableView:(UITableView *)tableView
| commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath |
| moveRowAtIndexPath:(NSIndexPath*)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath |
|
| レシーバーへの行の挿入または削除を行うよう指示する |
| 行を他の位置に移動するよう指示する |
|
-(NSInteger)tableView:(UITableView *)tableView
| numberOfRowsInSection:(NSInteger)section |
| sectionForSectionIndexTitle:(NSString*)title atIndex:(NSInteger)index |
|
| 指定セクションの行数を返す(必須) |
| 与えられた文字列とセクションタイトル要素番号を持つセクションの要素番号 |
|
-(NSString *)tableView:(UITableView *)tableView
| titleForFooterInSection:(NSInteger)section |
| titleForHeaderInSection:(NSInteger)section |
|
| 指定セクションのフッターの文字列 |
| 指定セクションのヘッダーの文字列 |
|
デリゲートは
UITableViewDelegateプロトコルに従う。
| メソッド名 | 動作 |
-(void)tableView:(UITableView *)tableView
| accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath |
| didDeselectRowAtIndexPath:(NSIndexPath*)indexPath |
| didEndEditingRowAtIndexPath:(NSIndexPath*)indexPath |
| didSelectRowAtIndexPath:(NSIndexPath*)indexPath |
| willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath |
willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath |
|
| 行がタップされた |
| 行が非選択になった |
| 編集モードが解除された |
| 行が選択された |
| 編集モードに入る前 |
| 特定行のセルを表示する前 |
|
-(CGFloat)tableView:(UITableView *)tableView
| heightForFooterInSection:(NSInteger)section |
| heightForHeaderInSection:(NSInteger)section |
| heightForRowAtIndexPath:(NSIndexPath*)indexPath |
|
| 現在セクションのフッター高さ |
| 現在セクションのヘッダー高さ |
| 現在位置の行高さ |
|
-(UIView *)tableView:(UITableView *)tableView
| viewForFooterInSection:(NSInteger)section |
| viewForHeaderInSection:(NSInteger)section |
|
| 指定セクションで表示するフッターのビューオブジェクト |
| 指定セクションで表示するヘッダーのビューオブジェクト |
|
-(NSIndexPath *)tableView:(UITableView *)tableView
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath |
| willDeselectRowAtIndexPath:(NSIndexPath *)indexPath |
| willSelectRowAtIndexPath:(NSIndexPath *)indexPath |
|
行の移動に伴う新しいインデックスパス
|
| 指定行が非選択になる前 |
| 指定行が選択される前 |
|
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath | 現在の行の編集形式
|
-(NSInteger)tableView:(UITableView *)tableView
indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath | 指定セクションの行のくぼみレベル
|
-(BOOL)tableView:(UITableView *)tableView
shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath | テーブルビューが編集モードにある間指定された行の背景がくぼまなければならないかどうか
|
-(NSString *)tableView:(UITableView *)tableView
titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath | 削除確認ボタンの文字列を変える
|
正直な所、テーブルビューの編集機能までは使ったことがないのでその辺りは不明。
基本的な表示処理は、以下のように記述すれば良い。
- (void)viewDidLoad
{
[super viewDidLoad];
self.title=NSLocalStr(@"SETUP");
//
NSLog(@"SetupViewController 各セクションの項目の作成");
// cell*は後述のUITableViewCell
// セッションごとにNSArrayにまとめる
NSArray *basic =[NSArray arrayWithObjects:cellMaxStringLength,cellVariableAutoDeclear,cellForcedSHIFTJISMode,nil];
NSArray *general=[NSArray arrayWithObjects:cellListFont,nil];
//
// sectionsと同じ順にすること
objects =[[NSArray alloc]initWithObjects:basic,general,nil];
//
// セクション名の設定
// objectsと同じ順にすること
// これがセクションを区切るkey名になるので、同じ物があると同じ分の幅が取られる
sections = [[NSArray alloc]initWithObjects: NSLocalStr(@"BASIC"),
NSLocalStr(@"GENERAL"),nil];
//
dataSource=[[NSDictionary alloc]initWithObjects:objects forKeys:sections];
//
// basic/generalはここで開放される(クラスインスタンスだから)
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
// セクション数を返す
{
// Return the number of sections.
return [sections count];
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
// セクションごとの名前を返す
{
return [sections objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
// セクションごとの行数を返す
{
// Return the number of rows in the section.
id key=[sections objectAtIndex:section];
return [[dataSource objectForKey:key]count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
id key=[sections objectAtIndex:indexPath.section]; // セクション名がキーとなる
return [[dataSource objectForKey:key]objectAtIndex:indexPath.row];
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
// セル内にアクセサリとしてつけたボタンが選択された
// アクセサリとしてつけたボタンは外部に現れないので、IBでは接続できない
{
NSLog(@"セル選択=%@",indexPath);
idx_row =indexPath.row;
idx_section =indexPath.section;
switch (idx_section) {
case SectionBASIC:
switch (idx_row) {
case RowMaxStringLength:
~
break;
}
break;
case SectionGeneral:
switch (idx_row) {
case RowFont:
~
break;
}
break;
}
}
UITableViewCell
UITableViewCellは、
UITableViewで表示するセル1つ1つを管理するビューである。
UITableViewCell
| プロパティ名 | 属性 | 内容 |
| UILabel *textLabel | RT | テーブル・セルの主な本文の内容のために使われるラベル
textLabel自体はReadonlyだが、.textは書き込み可能
|
| UITableViewCellAccessoryType accessoryType | | 通常状態でセルが使う標準的なアクセサリビュー
UITableViewCellAccessoryType(enum値)
| UITableViewCellAccessoryNone | アクセサリビューなし |
| UITableViewCellAccessoryDisclosureIndicator |  |
| UITableViewCellAccessoryDetailDisclosureButton |  |
| UITableViewCellAccessoryCheckmark |  |
|
| UIView *accessoryView | T | 通常状態でセルの右側で使われるビュー |
| UIView *backgroundView | T | セルの背景のビュー |
| UIView *contentView | RT | セルのコンテントビュー |
| UILabel *detailTextLabel | RT | セルの第二ラベル(存在時のみ)
detailTextLabel自体はReadonlyだが、.textは書き込み可能
|
| BOOL highlighted | G=isHighlighted | 強調表示表示するかどうか |
| UIImageView *imageView | RT | テーブルセルのイメージビュー |
| NSInteger indentationLevel | | セルがくぼんでいるときのくぼみレベル |
| CGFloat indentationWidth | | セルがくぼんでいるときのくぼみ幅(デフォルトは10.0ポイント) |
| NSString *reuseIdentifier | RC | 再使用できるセルを確認するのに用いられる識別子 |
| BOOL selected | G=isSelected | セルが選択中かどうか |
| UIView *selectedBackgroundView | T | 選択中のセルの背景ビュー |
| UITableViewCellSelectionStyle selectionStyle | | セル選択中のスタイル
UITableViewCellSelectionStyle(enum値)
| UITableViewCellSelectionStyleNone | 選択時に明瞭なスタイルを持たない |
| UITableViewCellSelectionStyleBlue | 青背景になる(デフォルト) |
| UITableViewCellSelectionStyleGray | 灰色背景になる |
|
| BOOL editing | G=isEditing | 編集モード |
| UITableViewCellAccessoryType editingAccessoryType | | 編集モードでのアクセサリービュー |
| UIView *editingAccessoryView | T | 編集状態でセルの右側で使われるビュー |
| UITableViewCellEditingStyle editingStyle | R | セルの編集状態のスタイル
UITableViewCellEditingStyle(enum値)
| UITableViewCellEditingStyleNone | 編集コントロールを持たない(デフォルト) |
| UITableViewCellEditingStyleDelete | 削除コントロールを持つ(赤丸-が表示される) |
| UITableViewCellEditingStyleInsert | 挿入コントロールを持つ(緑丸+が表示される) |
|
| BOOL shouldIndentWhileEditing | | テーブルビューが編集モードにいるときに背景をくぼませるかどうか |
| BOOL showingDeleteConfirmation | R | セルが削除確認ボタンを現在示しているかどうか |
| BOOL showsReorderControl | | 再配置コントロールを表示するかどうか(デフォルト=NO) |
「再配置コントロール」は灰色で、2重の水平線コントロールがセルの右側に表示される。
ユーザーはこのコントロールをドラッグしてテーブル内を再配置する。
誠に困ったことに、IBでは全てのプロパティへの設定が出来ない。
特に致命的なのはdetailTextLabel/textLabelへの設定が出来ないこと。
このため、わざわざcellの上にUILabelを貼り付けるという無駄なことをしなければならない。
IBのバグに近い仕様なので、早急に修正していただきたいところである。
というか、CellをIBで作ること自体が想定されてない?
私は多用しているのだが。
| メソッド名 | 動作 |
| -(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString*)reuseIdentifier |
セルをスタイルと再利用識別子で初期化する
再利用識別子は、メモリ上にキャッシュされたセルを再利用して表示を高速化するものだが、
セル数が少ないときはかえって面倒になるだけなので、無理して使う必要はない。
UITableViewCellStyle(enum値)
| UITableViewCellStyleDefault | 黒で左寄せのテキストラベルとオプションのイメージ・ビューによるセル(デフォルト) |
| UITableViewCellStyleValue1 | 黒で左寄せのテキストラベルと右寄せで小さい青色ラベル(通常アプリ用) |
| UITableViewCellStyleValue2 | 青で左寄せのテキストラベルと右寄せで小さい黒色ラベル(電話とコンタクトで使うらしい) |
| UITableViewCellStyleSubtitle | 左寄せのテキストラベルとその下に小さな灰色ラベル(iPodで使うらしい) |
|
| -(void)prepareForReuse | テーブルビューの再利用の準備 |
| -(void)didTransitionToState:(UITableViewCellStateMask)state |
セル状態が変更された後に呼び出される
UITableViewCellStateMask(NSUInteger値)
| UITableViewCellStateDefaultMask | 通常状態 |
| UITableViewCellStateShowingEditControlMask | 編集状態時 |
| UITableViewCellStateShowingDeleteConfirmationMask | 削除確認ボタンを表示中 |
|
| -(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated | 強調表示表示のON/OFF |
| -(void)setEditing:(BOOL)editing animated:(BOOL)animated | 編集モードのON/OFF |
| -(void)setSelected:(BOOL)selected animated:(BOOL)animated | セルを選択状態にする |
| -(void)willTransitionToState:(UITableViewCellStateMask)state | セル状態を変更する |
//スタイルを指定した生成
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:スタイル名 reuseIdentifier:CellIdentifier];
//空のセルを生成
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
// テーブルビューセル例文
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.textLabel.textColor = [UIColor blueColor];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
cell.selectionStyle = UITableViewCellSelectionStyleGray;
}
cell.textLabel.text = @"ほげ";
UITableViewController
UITableViewControllerは、UITableViewを制御するコントローラーである。
以下の処理も行ってくれる。
- nibファイルが親クラスのUIViewControllerのinitWithNibName:bundle:を通して指定されるならば
UITableViewControllerはテーブルビューをnibファイル中から読み込む。
それがない場合は、未調整のUITableViewオブジェクトを、正しい特質(Dimension)と自動リサイズマスクで新規作成する。
このビューには、tableViewプロパティー(後述)でアクセスできる。
- テーブルビューを含んでいるnibファイルが読み込まれるなら、データソースとデリゲートは
nibファイルで定められるそれらになる。
nibファイルが指定されない、あるいは、nibファイルがデータソースまたはデリゲートを定めないなら、
UITableViewControllerはデータソースとテーブルビューのデリゲートをselfに設定する。
- テーブルビューが初めて読み込まれるとき、テーブルビューコントローラーはテーブルビューのデータを再読み込みする(意味不明)。
アニメーションのあり・なしにかかわらず、セクションはクリアされ、テーブルビューが表示される。
UITableViewControllerクラスは、親クラスのviewWillAppear:メソッドでこれを実行する。
ただし、clearsSelectionOnViewWillAppearプロパティ(後述)により、この動作を抑制できる。
-
テーブルビューが現れるとき、コントローラーはテーブルビューのスクロールインジケーターを一瞬表示する。
UITableViewControllerクラスは、親クラスのviewDidAppearメソッド:でこれを実行する。
-
ユーザーがナビゲーションバーの「編集|完了」(Edit|Done)ボタンをタップしたら、
コントローラがテーブルの編集モードを切り替えるのは、親クラスのsetEditing:animated:メソッドで実装する。
アプリケーションでは、管理したい各々のテーブルビューのために、UITableViewControllerのカスタム子クラスを作成する。
initWithStyle:メソッド(後述)でコントローラを初期化するとき、
管理するテーブルビューが、単一かグループ化するかを指定しなければならない。
なぜなら、初期に作られるテーブルビューはテーブルの特質(セクション数、セクション毎の行数)や内容、
テーブルビューのデータ源とデリゲート~つまりUITableViewControllerオブジェクト自分自信~なしで生成されるからである。
loadViewまたは他の親クラスのメソッドをオーバーライドするかもしれないが、親クラスのメソッドを実行することが確実ならば、
通常最初のメソッドを呼び出すこと。
UITableViewController
| プロパティ名 | 属性 | 内容 |
| BOOL clearsSelectionOnViewWillAppear | | テーブルが表示されるとき、そのカレントセクションをクリアするかどうか
このときテーブルビューはviewWillAppear:メソッドを受信する。
|
| UITableView *tableView | T | コントローラーが管理しているテーブルビュー |