Androidでoverflowした要素をスクロール可能にするjQueryプラグイン


Androidでoverflowするとスクロールできない問題を解決するためにつくりました。

※(追記) iOSとかではCSSで"-webkit-overflow-scrolling: touch;"にすればよいそうです。

ソースコード

使い方

CSS

#hoge {
    overflow:auto;//Androidは強制的にhidden的な挙動になる
    width:320px;
    height:400px;
}

JS

$("#hoge"). overflowScroll();

iOSでもoverflowを設定すると慣性スクロールが効かなくなるので有用かもしれませんが、
よほどでなければUAを判定してAndroidだけ適応するほうがいいと思います。

仕組み

touchStartで取得したポイントをと現在の指の位置の差分をscrollTopに設定しているだけです。
模式的に書くと次のようなかんじです。

タッチ開始

$target.on("touchStart", function(event) {
        event = event.originalEvent;
        var touch = event.touches[0];
        touchStartX = touch.pageX;
        touchStartY = touch.pageY;
});

タッチ中(ドラッグ中)

$target.on("touchMove", function(event) {
        event = event.originalEvent;
        var touch = event.touches[0];
        touchX = touch.pageX;
        touchY = touch.pageY;

        $target.scrollLeft(touchStartX - touchX);
        $target.scrollTop(touchStartY - touchY);
});

タッチ完了

$target.on("touchEnd", function(event) {
        event = event.originalEvent;
        var touch = event.touches[0];
        touchStartX = touch.pageX;
        touchStartY = touch.pageY;

        //何かあれば
        //...
});

実際にはtouchEndで直前の touchX/touchYとの差分をもとに話した時の指の速度を割り出し
それをもとに慣性スクロールっぽくするよう試みてます。

$target.on("touchEnd", function(event) {
        event = event.originalEvent;
        var touch = event.changedTouches[0];

        touchSpeedX = (touchX - touch.pageX);
        touchSpeedY = (touchY - touch.pageY);

        intervalID = setInterval(afterMoving, INTERVAL_TO_MOVE);
});

function afterMoving() {
        //速度があまりにも小さくなったら止まったことにする。
        if ((Math.abs(touchSpeedX)<LIMIT_TO_STOP && Math.abs(touchSpeedY)<LIMIT_TO_STOP)) {
            clearInterval(intervalID);
            return;
        }

        var oldX = $target.scrollLeft(),
            oldY = $target.scrollTop();

        //摩擦係数をかけて減速
        touchSpeedX *= FRICTION;
        touchSpeedY *= FRICTION;

        $target.scrollLeft(oldX + Math.round(touchSpeedX));
        $target.scrollTop(oldY + Math.round(touchSpeedY));
}

この記事は2013-08-19の記事の転載です。