最近 WebView を利用したスマートフォン(iPhone/Android)アプリを
作成する機会がありました。
フリックで行を動かしたりページを変えてみたりしたのですが、
なんとこれでページのスクロールができなくなってしまいました!
原因は、touchstart、touchmove、touchendに紐づけていた
関数で利用したpreventDefault()。
touchイベントでpreventDefault()を使うと、
デフォルトのスクロールが効かなくなってしまうんですね!(@▽@)
これを回避するために、今回iScrollというものを使ってみました。
え?そもそもpreventDefault()使うのが間違っている?
おっしゃるとおりなんですが、画面の上をスワイプしたりページをAJAX通信で
変更させてみたりするときにpreventDefault()を使わざるをえなかったんですorz
----------
では、iScrollの基本的な使い方を解説していきます。
■この記事の対象者■
下記を満たす方
jQuery を触ってみたことがある html を書いてみたことがある cssでの「#hoge」や「.hoge」といった 書き方が何を意味しているか分かる ■作成するページ■
ページの一部をスクロールできるページ
まずは
iScroll 4 から iscroll-4.zip をダウンロードします。
ダウンロードしたzipを解凍して、iscroll.jsがあるのを確認します。
iscroll.jsを入手できたら、htmlとcssを準備します。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <title></title> <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script> <script type="application/javascript" src="./src/iscroll.js"></script> <style type="text/css" media="all"> /* iscrollとは関係ないスタイル */ div { margin: 0; padding: 0; } #wrapper { padding: 10px; background-color: #ffaaff; } #wrapper-scroll { height: 100px; background-color: #ffffff; } #layer01 { height: 150px; background-color: #aaffff; } #layer02 { height: 150px; background-color: #ffffaa; } </style> </head> <body> <div id="wrapper"> <div id="wrapper-scroll"> <!-- wrapper --> <div id="layer01"> <!-- scroller --> <script type="text/javascript"> for(var i = 1; i <= 9; i++) { document.write(i + "行目<br />"); } </script> </div> <div id="layer02"> <script type="text/javascript"> for(var i = 1; i <= 9; i++) { document.write(i + "行目<br />"); } </script> </div> </div> </div> </body> </html>見た目はこうなります。
1つ1つ説明していきますネ。
■プラグインへのリンク
<head>内で jQuery と flickSimple にリンクを張ります。
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script> <script type="application/javascript" src="./src/iscroll.js"></script>iScroll は jQuery を使用しているので、
iScroll の前に jQuery にリンクを張ってあげてください。
iScroll のスクリプトのパスは、どこに iScroll をダウンロードしたかで変わります。
■html
<div id="wrapper"> <div id="wrapper-scroll"> <!-- wrapper --> <div id="layer01"> <!-- scroller --> <script type="text/javascript"> for(var i = 1; i <= 9; i++) { document.write(i + "行目<br />"); } </script> </div> <div id="layer02"> <script type="text/javascript"> for(var i = 1; i <= 9; i++) { document.write(i + "行目<br />"); } </script> </div> </div> </div>id が「wrapper-scroll」の中身をスクロールできるように組んでいます。
iScroll適用後にスクロールしているのが分かりやすいよう、
wrapper-scroll の中身が wrapper-scroll より大きくなるように
CSSで設定しています。
Google Chrome の Developer tools で確認すると、wrapper-scroll の位置が分かりますネ。
スクロール時に見えている高さを決める wrapper-scroll 部分は
ページ全体で一意に決まる要素になっている必要があります。
なので、id名をふってあげましょう。
■iScroll を適用する。
細かい説明は後回しにして、iScroll を適用します。
<head>内に下記を追加してください。
<script type="text/javascript"> $(window).load(function(e) { new iScroll("wrapper-scroll"); }); </script>new iScroll()の引数にはフリックさせる範囲を示す要素の id 名を指定します。
iScroll を適用すると、見た目がこのように変わります。
一番下までスクロールするとこんな感じ。
iScroll 適用前と見た目がだいぶ変わりましたね。
id が layer02 の要素は見えもしません。
オマケに生成された html を Developer tools で確認すると、
なんだかごちゃごちゃしているのが分かります。
ここで、iScroll の仕組みを説明しましょう。
iScroll は new iScroll() の引数で指定した要素をスクロールの表示画面に、
その要素の1番目の子供を実際にスクロールして見たい html とみなします。
なので、new iScroll() の引数に指定した id="wrapper-scroll" の要素の
範囲のみが見えるようになりました。
そして、1番目の子供の id="layer01" の要素をスクロールして見れるようになっています。
2番目の子供は無視されてしまうので、下までスクロールしても見えません。
でも、消されたわけではないので、ちゃんといます。
iScroll は実際にスクロールしたい要素を動かしてスクロールしているように見せかけています。
なので、id="layer01" に指定された style の値はスクロールする度に変化します。
また、iScroll は独自のスクロールバーを出すので
id="wrapper-scroll" の最後にスクロールバー用の<div>が追加されています。
スマフォではスクロール時だけスクロールバーが見えるようになります。
----------
この状態では画面の一部分しかスクロールできませんが、
wrapper-scroll と 1番目の子供を画面全体を囲む div にしてあげれば、
画面全体をスクロールすることができます。
■iScroll 注意点
iScroll を適用すると、長押し(ロングタップ)でコピー・ペーストダイアログが表示されなくなります。
これは、touchstart を受け取った場合に preventDefault() を実行しているためです。
長押し(ロングタップ)を無効化したくない場合は、
iscroll の iScroll = function・・・ 内を下記のように改造します。
onRefresh : null, onBeforeScrollStart : function(e) { // e.preventDefault(); // comment out : 長押し有効化のため }, onScrollStart : null, // onBeforeScrollMove: null, // comment out onBeforeScrollMove : function(e) { // add : デフォルトスクロール無効化のため e.preventDefault(); },----------
では、今回はここまで!