UIScrollViewでの画像表示高速化、最適化についてのtipsその1
60FPS維持しつつ画像描写がめちゃムズい
UIScrollViewは60FPSで動いてるとの事で、
これを維持しつつ、
画像をなめらかにするのは難しい。工夫が必要。
色んな記事でこの問題は良く目にします。
解決策に「imageNamedを使おう」を良くみるが。。。
[UIImage imageNamed:XXX]は画像キャッシュし、読み込みが早い、
[UIImage imageWithContentsOfFile:XXX]は画像キャッシュせず、読み込みが遅い
ってなわけで「imageNamedを使おう!」
で終わっている記事が多いのですが、
imageNamedでもスクロール中に表示すると、
初回読み込み時につっかかる感触がある。
(私の意見としては後述の画像展開が悪さしているのであって、これは本質じゃないと思ってますが、深追いは止めときます)
圧縮形式画像→展開が重い
初回読み込み時だけってなんでかなー・・・。と模索してたところ、
どうやら「圧縮画像ファイル→展開」処理に
すごい時間かかってるらしい事が分かった。
展開を自前でやってみる
ViewDidLoadの段階で無圧縮展開してしまえば、
快適なスクロールビューが実装できるのではと思いたち、
サンプルコードを書いてみる事に。
nonCompressImageメソッドをViewDidロードで呼び、
圧縮画像ファイル→展開を自分でやってます。
自分で展開せずに、UIImageViewに展開を任せた場合の
つっかかりを確認する場合は、コメントアウトしている部分を
入れ替えてみてください。
つっかからなくなった!
つっかかりが一切消えました。やった。
後はメモリへの負担を気にしながらNSCacheなりで
画像のキャッシュ化をしてあげれば
imageWithContentsOfFileのパターンでの
高速表示もできますね。
これもかなり需要ありそうなのでtipsその2でのネタにしたいと思います。
今回は割と自分の勉強にもなりました。ScrollView最適化に
詳しくなっておくと、色々重宝されそうなのでもっと勉強します。
#import "ViewController.h" @interface ViewController (){ UIImageView* imageView; UIImage* image; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UIScrollView *sv = [[UIScrollView alloc] initWithFrame:self.view.bounds]; UIView *uv = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height*5)]; imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, self.view.frame.size.height*2, self.view.frame.size.width,self.view.frame.size.height)]; [uv addSubview:imageView]; [sv addSubview:uv]; sv.contentSize = uv.bounds.size; sv.delegate = self; [self.view addSubview:sv]; image = nonCompressImage([UIImage imageNamed:@"sample.png"]); } -(void)scrollViewDidScroll: (UIScrollView *)scrollView{ int page = scrollView.contentOffset.y / scrollView.frame.size.height; if(page==2){ //こっちのほうに変えるとつっかかる。 //imageView.image = [UIImage imageNamed:@"sample.png"]; //こっちに変えるとつっかからない imageView.image = image; } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } static UIImage * nonCompressImage(UIImage *image) { UIGraphicsBeginImageContext(CGSizeMake(image.size.width, image.size.height)); [image drawAtPoint:CGPointMake(0,0)]; image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } @end