iphoneアプリ開発日記その8
webView にスクロールボタンをつけよう
その動機
最近スマホを使っていると、指が痛くなることがある。
果たして手の油が少ないのか皮膚が弱いのか
まあそんなこんなで、ボタンタップでスクロールした方が、
指に負担が少なかろうと考えました。
実現へのアプローチ
さて、ボタンスクロールをどうやって実現するのだろう。
当初は webview にそれっぽい API があるんじゃないかなーと考えていました。
実際調べてみると、どうも API なんぞ無い模様。
ただし、webview から javascript が実行できるようで、それを使ってスクロールが出来るようでした。
さらに調べてみると、webview で jquery を使えるらしい。
面白そうなんでこれにしよう
jquery を読み込む
まず、jquery 本体をダウンロード→ここ
バージョンは 1.10.1 だった。
これで jquery が使えるようになった。
一応動作確認をしておく
以下のコードを、適当なボタンとかに設定して実行する
// load jquery NSString *path = [[NSBundle mainBundle] pathForResource:@"jquery-1.10.1" ofType:@"js"]; NSString* jqueryMain = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; [_webView stringByEvaluatingJavaScriptFromString:jqueryMain]; NSString *script = @"alert($().jquery);"; [_webView stringByEvaluatingJavaScriptFromString:script];
結果
ちゃんと動いているようだ。
jquery のロードタイミング
さて、ひとまず jquery が動いたわけだが、jquery の本体を毎回読み込む必要はないわけで。
どこかで一回読み込めばよいだろう。
とりあえず、viewDidLoad で読み込んでみる。
… あれ? 動かない。
なんだろう。スコープの関係だろうか。
jquery 本体のコードを static にしてみた
→ 動かない。
うーむ、毎回呼ばないとだめなのだろうか。
試しに、ボタンを複数用意して、片方だけに jquery 読み込み処理を書いてみた
→ jquery 読み込み処理を書いたボタンを押したあとなら、書いてない方も動く
ふむ、一度読み込んでしまえばOK なわけか。
ということは、読み込むタイミングが悪いということだな。
そうなると、読み込ませるタイミングは URL 読み込みが終わってからかなー
このへんか → webViewDidFinishLoad
試してみる
@interface WebViewController () @property NSString* jqueryMain; @end - (void)viewDidLoad { [super viewDidLoad]; // いろいろ初期化処理 // load jquery NSString *path = [[NSBundle mainBundle] pathForResource:@"jquery-1.10.1" ofType:@"js"]; self.jqueryMain = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; } - (void)webViewDidFinishLoad:(UIWebView *)webView { [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; // load jquery [_webView stringByEvaluatingJavaScriptFromString:self.jqueryMain]; }
これで一度だけ読み込めばよくなった。
スクロール機能の実装
ここまで来たら、あとは jquery を使うだけである。
だが、jquery というか javascript はほとんどやってないので、これも調べながらになる。
このへん を参考に、どうするか考える。
見たところ、scrollTop で指定した位置に移動するようだ。
あとは以下の関数を組み合わせればよさげ
$('body').offset().top | ページ全体の先頭位置 |
$('body').height() | ページ全体の高さ |
$(window).scrollTop() | ウィンドウの先頭位置 |
$(window).height() | ウィンドウの高さ |
考え方としては、こんな感じ
「ページ全体の先頭位置 + 全体の高さ 」に移動すれば、一番下まで移動できる。
「ウィンドウの先頭位置 +ー ウィンドウの高さ」で移動すれば、上下に1画面分移動する
実装してみる
- (IBAction)pressUpward:(id)sender { NSString *script = @"$('body').animate({scrollTop:$(window).scrollTop() - $(window).height()});"; [self execJQuery:script]; } - (IBAction)pressDownward:(id)sender { NSString *script = @"$('body').animate({scrollTop:$(window).scrollTop() + $(window).height()});"; [self execJQuery:script]; } - (IBAction)pressPageEnd:(id)sender { NSString *script = @"$('body').animate({scrollTop:$('body').offset().top+$('body').height()}, 'fast')"; [self execJQuery:script]; }
これでページスクロール機能が実装できました。
本当は、ページの上下限を考えて、オーバーするようなら0とか最大値を返そうと思っていたのですが、
特に対応しなくても問題なさそうでした。
webkit か jquery 側でちゃんとやってくれているみたい。