2012年3月21日水曜日

Twitter Clientライクな可変長UITableViewCell

Twitterクライアントでよく見る可変長のUITableViewCellを作成してみました。(ソース)

ざっくりと調べたところ、UILabelを用いると簡単に実装できるみたいなんですが、これの問題点はhrefなどのリンクが使えないところ。

僕のよく使ってるechofonなんかは、aタグだけじゃなく@XXXXとかもリンクで飛べる実装にしているみたいなので、これも視野に入れて実装してみたいな、と。

で作ってみた。





実装は大まかに以下のよう。


1.tableView:heightForRowAtIndexPathにとりあえずの高さ100.0を返す。

2.tableView:cellForRowAtIndexPathでUITableViewCellを作成する。高さ1のUIWebViewを作成し、loadHTMLStringでテキストを読ませておく。

3.tableViewをreloadするためにタイマーをセット

4.再度、tableView:heightForRowAtIndexPathが呼ばれるのでUIWebView.scrollView.contentSize.heightによりテキスト表示に必要な高さを取得し、呼び出しもとに返す。

5.UIWebViewのdrawRectも呼ばれるので、高さを再調整。
ソースコードの概要を説明していきます。


詳細はgithubみてください。



まずはUITableViewController

@implementation VHTableViewController
{
// 省略
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    int row = [indexPath row];
    
    VHTableViewCell *cell = [cellDict objectForKey:[NSNumber numberWithInt:row]];
    if(cell == nil){
        cell = [[VHTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil index:[indexPath row]];
        // 一度作ったセルを覚えておく
        [cellDict setObject:cell forKey:[NSNumber numberWithInt:[indexPath row]]];
        // 3秒後にtableViewをリロードするようにタイマーをセット。
        // タイマーにしておくと、連続して再描画要求が来たときもOSがいい感じにはしょってくれてる。
        [self setTableReloadTimer];
    } 
    return cell;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{

    int row = [indexPath row];
    VHTableViewCell *cell = [cellDict objectForKey:[NSNumber numberWithInt:row]];
    if(cell == nil){// はじめに呼ばれた場合
        return 100.0;
    }
    // 二回目以降は必要な高さ
    return cell.webView.scrollView.contentSize.height;
    
}
// 省略
}
@end

んでUITableViewCell(のサブクラス)のコード 本当はUITableViewCellのサブクラス一個でこれを実現できると、使い回しが相当よかったんだけど、ちょっとやり方思いつかなかった。

高さ可変のセルなんか需要たくさんあるだろうから、apple様に標準提供していただけるとうれしいんだけど、作り的に難しいのかなー。