2011年11月19日土曜日

UIWebView.scrollView に対して KVO を使うと色々面白い

iOS 5より、UIWebViewにscrollViewプロパティが追加され、たとえばスクロールを無効にしたりステータスバーをタップしても一番上に戻らないようにしたりなど、UIWebViewのスクロール周りの処理を外から自由に触れるようになりました。ですが便利なのはこれだけではありません。KVOの仕組みを使うことで、さらにUIWebViewを便利に使うことができます。ここでは私が使っている中で一番のおすすめをご紹介します。

■UIWebViewの描画しているHTMLのcontentSizeを非同期的に、リアルタイムで取得する
UIWebview.scrollViewのcontentSizeプロパティは、UIWebViewの描画しているHTMLの大きさ(contentSize)と同じ値になります。この性質を利用して、contentSizeプロパティにKVOを貼ると、UIWebViewの描画しているHTMLの大きさ(contentSize)が変わったタイミングで通知を受け取ることができます。こんなコードになります。
- (void)viewWillAppear:(BOOL)animated
{
  [self.webView.scrollView addObserver:self forKeyPath:@"contentSize" options:0 context:NULL];
  [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://akisute.com"]]];
}
- (void)viewWillDisappear:(BOOL)animated
{
  [self.webView.scrollView removeObserver:self forKeyPath:@"contentSize"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
  NSLog(@"%s", __func__);
  NSLog(@"  * contentSize = %@", NSStringFromCGRect(self.webView.scrollView.contentSize));
}
このテクを使うことで、例えばUIWebView自体をスクロールさせないようにした上で通知を受け取ってUIWebViewのframeをどんどん更新するようにし、UIScrollViewの中に埋め込んでしまってUIImageViewやUILabelのようにして使うみたいなUIを作ることが簡単にできます。HTMLの高さに依存するコードも作れますし、なかなか面白いですよ。iOS 5はもちろん、iOS 4でも動作します。(余談で解説)

■余談
UIWebViewのscrollViewプロパティは実はiOS 4のころからPrivate APIとして存在します。ですがiOS 5よりパブリック扱いになったおかげか、iOS 4向けのアプリでscrollViewプロパティを触っていてもリジェクトされたりクラッシュすることなく普通に使えるので非常に嬉しいです。iOS 3では使えませんのであしからず。