Cocoaの日々: UITableView のヘッダの高さを変える
この時はヘッダのリサイズが完了した後、テーブル本体の位置が調整されるようになっていた。これをヘッダのリサイズアニメーションと同時にテーブル本体の位置調整をアニメーション付きで行えるようにする。
実現方法
正攻法はないので今回も少しトリッキー。今回はダミーセクションを用意し、これの高さを調整することでテーブル本体のアニメーションを実現する。
イメージ:
1. まず高さ0セルをひとつだけ持つ Section 1 を用意しておく(図の左の状態)。
2. Headerの高さ増加開始
3. Headerの高さが増加すると同時に Section 1 内のセルの高さを増やし、アニメーションさせる(図の右の状態)。
すると Headerが下へ伸びるのと同時に Section2 以下のテーブル本体も下へ移動する。
実装
ポイントは、section 1 (indexPath.section == 0) をダミーセクションとして扱うこと。UITableViewDataSourceのメッソドで section 0 とそれ以外とで処理を分けていく。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == 0) { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"CELL1"]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"CELL1"] autorelease]; UIView* view = [[[UIView alloc] initWithFrame:CGRectZero] autorelease]; cell.backgroundView = view; } return cell; } else { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"CELL2"]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"CELL2"] autorelease]; } cell.textLabel.text = [array_ objectAtIndex:indexPath.row]; return cell; } }section == 0 の時には UITableViewCell.backgroundView へ大きさ0のビューを設定している。こうすることで枠や背景の無い高さ0のセルを用意することができる。
もちろんデリゲートで高さも調整する。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == 0) { return spaceCellHeight_; } else { return tableView.rowHeight; } }
メンバ変数 spaceCellHeight_ は Headerアニメーション時に調整する。
- (IBAction)changeHeader:(id)sender { CGRect frame = self.headerView.frame; if (headerOpened_) { frame.size.height = 50.0; spaceCellHeight_ = 0.0; } else { frame.size.height = 100.0; spaceCellHeight_ = 50.0; } NSIndexPath* path = [NSIndexPath indexPathForRow:0 inSection:0]; [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:YES]; [UIView animateWithDuration:0.25 animations:^{ self.tableView.tableHeaderView.frame = frame; } completion:^(BOOL finished){ // self.tableView.tableHeaderView = nil; // self.tableView.tableHeaderView = self.headerView; }]; headerOpened_ = !headerOpened_; }ポイントは reloadRowsAtIndexPaths:withRowAnimation:
これを呼びだすと特定のセルの再描画が行われる。この前後でセルの高さが異なると、その変更過程がアニメーションとなる。なおダミーセクション(セル)を使うことで、前回のように UITableView.headerView へ一時的に nil を入れる必要がなくなった(コメントアウトしてある箇所)。
サンプル
静止図だとちょっと分かりにくいが実行時のスクリーンショットを並べておく。
初期状態。
アニメーション開始。前回と比べると Headerがテーブルへかぶらず、全体的に下に移動しているのがわかる。
アニメーション完了。
ソースコードは GitHub からどうぞ。
TableHeader at 2010-08-14 from xcatsan's iOS-Sample-Code - GitHub
その他
この方法を取る場合の制約がいくつかあるので書いておく。
1. アニメーション速度が固定
iOS標準のアニメーションの長さは大抵 0.2秒間で終わるようになっている。今回テーブル本体のアニメーションはこれに従うため、 Headerのアニメーションの長さもそれと同じ 0.2秒に合わせる必要がある。なお処理上の遅延を考慮すると 0.25秒ぐらいが適当のようだ。
2. Headerの表示領域の高さが実体の高さと一致しない
開閉で Header の高さが異なるが、UITableViewにはそれを教えていない。現状は特に問題ないようだが、今後の iOSバージョンアップで問題が出る可能性がなくもない。
Responses
Leave a Response