UITableView のヘッダの高さを変える(その2:アニメーション)

2010年8月14日土曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

以前、UITableView のヘッダの高さを変えるコードを紹介した。

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

人気の投稿(過去 30日間)