こんにちは、豪(たけし)です。
UITableViewでの縦スクロールが妙に重いケース、良くありますね。
今回はHotel.jpのiPhoneアプリで縦スクロールをスムーズに高速に動かすために
行っていることをご紹介します。
Hotel.jpアプリのホテルの検索結果画面では、1つのセルの中にテキストラベルが
15個+画像2つ、しかもテキストラベル14個は画面左のタブを押すと横移動も
するといういかにも重そうなインターフェースなのですが、iPhone4であれば
スムーズに縦スクロールします。
検索結果画面

動画(30~40秒目が検索結果画面です)
ここ苦労したんです・・・。実装方法をざっとお話します。
最初は楽をしてやろうとUITableViewCellのNibを作ったのですが、
1つのセルにUILabelを15個並べて更に横に移動するようにすると
もうスクロールと呼べないコマ送りのような動きになりました。
そこで、Nibを使わないようにしたのですが、普通にUITableViewCellに
UILabelをaddSubviewしていくとまだスクロールが遅い。
そこで調べてわかったのは、必要な文字だけUITableViewCellに描き
こんでしまえば早くなるという原理でした。
UITableViewCellにUILabelとかのっけるから重くなるんです。
(本来のせても軽快にスクロールするのがベストですが)
参考にしたサイトがいくつかあるのでそれと一緒に説明します。
まず、1つ目
Apple TableViewSuite sample
このコード中の5_CustomTableViewCellを参考にしています。
実はこれ、AppleがオリジナルではなくTweetieの作者が考案した
ものをAppleがパクった参考にした(英語)ようです。
このソースコード長いですね。知っておけば役に立ちますが、
ここでは以下の部分を知っておけばいいです。
ファイル:5_CustomTableViewCell/Classes/TimeZoneWrapper.m
予めstaticで必要な部品を持たせておいて、セルを表示するときに何度も
再利用しています。[UIImage alloc] init]ではなく[UIImage imageNamed]を
使っている部分はimageNamedのキャッシュを効かせたいからなのでしょうか?
(キャッシュが効くならstaticで持たせる必要がそもそもないのかも?
試していませんが、確実な方法として私はstaticを使って書いています。)
二つ目
先ほども出たTweetieの作者のページにある
ABTableViewCell(FastScrolling.zip内)なのですが、どうもファイルがDLできないですね・・・
下のブログでサンプルプロジェクトに同じものが使われているのでダウンロードしてみて下さい。(リンクに修正版と書かれている方です)
[iPhone] テーブルのスクロールが遅いので高速化に挑戦中(苦戦中)
その中のABTableViewCellとFastTableViewCellの動きを全て把握して下さい。
これが要です。
簡単に言うとこんなイメージ。
通常
・UITableViewCellにUILabelのインスタンスを置いて、そのtextプロパティに値を入れておく。
改善版
・UILabelを使わず、drawRectメソッドが呼び出されたら鉛筆を持たせて、セルに文字を書けと指示を出す。
このFastTableViewCellを使うだけで相当滑らかに動くのですが、先ほどのTimeZoneWrapper.mで
staticを使ったインスタンスを保持しておく方法をプラスすれば、スクロールが更に滑らかになり、
スクロール中の引っ掛かりが軽減されます。
(Hotel.jpアプリのTableViewCellは横移動もするので、実際にはABTableViewCellも
FastTableViewCellも使わず0から作っています)
ちなみに、ABTableViewCellについて追加でこちらの人がコメント(英語)してますが、
まとめると、以下の2点をすると良いそうです。
・initWithFrameではなくinitWithStyleを使う
・tableView:cellForRowAtIndexPath:のメソッドのreturn cellの直前に[cell setNeedsDisplay]の1行を追加する
三つ目
ホテル写真部分はLazy loadingさせています。読み込み開始の
タイミングなどまだ改善の余地があるのですが、これをしていないUITableView
はあまり見ないので、ここでは割愛。
四つ目
tableView:cellForRowAtIndexPath:の中で行われる処理が軽いほど滑らかにスクロールします。
そのため、事前に実行できる処理はやっておくのが良いでしょう。
Hotel.jpアプリのホテル検索結果のページでは各ホテルへの現在地からの距離が表示されています。
この部分はセルが表示される時ではなく、事前に距離計算され、文字列化
されたものを保持しています。そのため、tableView:cellForRowAtIndexPath:が
呼び出された時は、その文字をセルに描くだけで良い状態になっています。
最後に
透過性のビューを使わないようにするなど、その他にも少しだけ技があります(ただし、あまり大きな効果は期待できません)。
以下を参考にして下さい。
[iOS] TableView スクロールパフォーマンスの改善
[iPhone] テーブルのスクロールが遅いので高速化に挑戦中(苦戦中)
iPhoneアプリ開発をする方は最初にぶつかる(ぶつかった!)壁かと
思うので、一助になれば嬉しいです!
UITableViewでの縦スクロールが妙に重いケース、良くありますね。
今回はHotel.jpのiPhoneアプリで縦スクロールをスムーズに高速に動かすために
行っていることをご紹介します。
Hotel.jpアプリのホテルの検索結果画面では、1つのセルの中にテキストラベルが
15個+画像2つ、しかもテキストラベル14個は画面左のタブを押すと横移動も
するといういかにも重そうなインターフェースなのですが、iPhone4であれば
スムーズに縦スクロールします。
検索結果画面

動画(30~40秒目が検索結果画面です)
ここ苦労したんです・・・。実装方法をざっとお話します。
最初は楽をしてやろうとUITableViewCellのNibを作ったのですが、
1つのセルにUILabelを15個並べて更に横に移動するようにすると
もうスクロールと呼べないコマ送りのような動きになりました。
そこで、Nibを使わないようにしたのですが、普通にUITableViewCellに
UILabelをaddSubviewしていくとまだスクロールが遅い。
そこで調べてわかったのは、必要な文字だけUITableViewCellに描き
こんでしまえば早くなるという原理でした。
UITableViewCellにUILabelとかのっけるから重くなるんです。
参考にしたサイトがいくつかあるのでそれと一緒に説明します。
まず、1つ目
Apple TableViewSuite sample
このコード中の5_CustomTableViewCellを参考にしています。
実はこれ、AppleがオリジナルではなくTweetieの作者が考案した
ものをAppleが
このソースコード長いですね。知っておけば役に立ちますが、
ここでは以下の部分を知っておけばいいです。
ファイル:5_CustomTableViewCell/Classes/TimeZoneWrapper.m
static UIImage *q1Image;
static UIImage *q2Image;
static UIImage *q3Image;
static UIImage *q4Image;
<省略>
+ (void)initialize {
// Unlikely to have any subclasses, but check class nevertheless.
if (self == [TimeZoneWrapper class]) {
<省略>
q1Image = [[UIImage imageNamed:@"12-6AM.png"] retain];
q2Image = [[UIImage imageNamed:@"6-12AM.png"] retain];
q3Image = [[UIImage imageNamed:@"12-6PM.png"] retain];
q4Image = [[UIImage imageNamed:@"6-12PM.png"] retain];
}
}
予めstaticで必要な部品を持たせておいて、セルを表示するときに何度も
再利用しています。[UIImage alloc] init]ではなく[UIImage imageNamed]を
使っている部分はimageNamedのキャッシュを効かせたいからなのでしょうか?
(キャッシュが効くならstaticで持たせる必要がそもそもないのかも?
試していませんが、確実な方法として私はstaticを使って書いています。)
二つ目
先ほども出たTweetieの作者のページにある
ABTableViewCell(FastScrolling.zip内)なのですが、どうもファイルがDLできないですね・・・
下のブログでサンプルプロジェクトに同じものが使われているのでダウンロードしてみて下さい。(リンクに修正版と書かれている方です)
[iPhone] テーブルのスクロールが遅いので高速化に挑戦中(苦戦中)
その中のABTableViewCellとFastTableViewCellの動きを全て把握して下さい。
これが要です。
簡単に言うとこんなイメージ。
通常
・UITableViewCellにUILabelのインスタンスを置いて、そのtextプロパティに値を入れておく。
改善版
・UILabelを使わず、drawRectメソッドが呼び出されたら鉛筆を持たせて、セルに文字を書けと指示を出す。
このFastTableViewCellを使うだけで相当滑らかに動くのですが、先ほどのTimeZoneWrapper.mで
staticを使ったインスタンスを保持しておく方法をプラスすれば、スクロールが更に滑らかになり、
スクロール中の引っ掛かりが軽減されます。
(Hotel.jpアプリのTableViewCellは横移動もするので、実際にはABTableViewCellも
FastTableViewCellも使わず0から作っています)
ちなみに、ABTableViewCellについて追加でこちらの人がコメント(英語)してますが、
まとめると、以下の2点をすると良いそうです。
・initWithFrameではなくinitWithStyleを使う
・tableView:cellForRowAtIndexPath:のメソッドのreturn cellの直前に[cell setNeedsDisplay]の1行を追加する
三つ目
ホテル写真部分はLazy loadingさせています。読み込み開始の
タイミングなどまだ改善の余地があるのですが、これをしていないUITableView
はあまり見ないので、ここでは割愛。
四つ目
tableView:cellForRowAtIndexPath:の中で行われる処理が軽いほど滑らかにスクロールします。
そのため、事前に実行できる処理はやっておくのが良いでしょう。
Hotel.jpアプリのホテル検索結果のページでは各ホテルへの現在地からの距離が表示されています。
この部分はセルが表示される時ではなく、事前に距離計算され、文字列化
されたものを保持しています。そのため、tableView:cellForRowAtIndexPath:が
呼び出された時は、その文字をセルに描くだけで良い状態になっています。
最後に
透過性のビューを使わないようにするなど、その他にも少しだけ技があります(ただし、あまり大きな効果は期待できません)。
以下を参考にして下さい。
[iOS] TableView スクロールパフォーマンスの改善
[iPhone] テーブルのスクロールが遅いので高速化に挑戦中(苦戦中)
iPhoneアプリ開発をする方は最初にぶつかる(ぶつかった!)壁かと
思うので、一助になれば嬉しいです!
ここを押してダウンロードしてね





