[JavaScript] Wink toolkit Scroller 7つの改造まとめ

  • このエントリーをはてなブックマークに追加

最近Android、iOS両対応のスマフォ用JS開発をしていて、ページの部分縦スクロールにWink toolkitというライブラリを使用しました。
そこで、付属のスクローラー(wink.ui.layout.Scroller)の不具合解消やチューニングについてまとめます。

Wink toolkit – A mobile JavaScript framework to build great webapps
http://www.winktoolkit.org/

なお、縦スクロール用の修正内容であり、横方向では検証していませんのでご注意ください。
縦スクロールのデモページは以下になります。

test_scroller
http://www.winktoolkit.org/documentation/wink/ui/layout/scroller/test/test_scroller.html?theme=default

スクロールバーの長さと移動範囲の改善

上記デモサイトでは一見普通の動きをしていますが、スクロールする内容物の高さをある程度まで短くすると、スクロールバーの表示がおかしくなります。
試しにサンプルデモ(text_scroller.html)の下記部分でリストの要素数を半分の70程度にしてみると違いがわかると思います。

test_scroller.html:66

    var scrollerHelper = 
    {
        nbItem: 140, // ここを70にしてみる
        items: [],
        scrolling: false,
        sliding: false,
        currentStage: null,
        selectTimer: null,
        nodePreselected: null,
        nodeSelected: null,

こうすると一番下までスクロールバーが到達しなくなります。
wink.ui.layout.Scroller.Scrollbar.updateSize()の下記部分をコメントアウトすることで改善されます。正直どうしてこうなっているのか理解はしていません。

scroller.js:1194

        if (viewportSize < contentSize) {
            this._view.ratioSize = (this._view.viewportSize / this._view.contentSize);
            //var sizeAdapter = 0.11 * (this._view.contentSize / this._view.viewportSize) + 0.89; // linear function
            //this._view.ratioSize *= sizeAdapter;
        } else {
            this._view.ratioSize = 1;
        }

加えて、実はスクロールバーの描画幅の指定が間違ってるので、直しました。あまり必要性はないかもしれません。
wink.ui.layout.Scroller.Scrollbar._resize()の下記部分です。

scroller.js:1437

//      wink.fx.apply(this._canvasNode, {
//          width: sizeX,
//          height: sizeY
//      });
        this._canvasNode.width = sizeX;  // 追記
        this._canvasNode.height = sizeY; // 追記

スクロールバーの位置をずらす

何気に幅は指定できるようになっているのに、位置は変えられませんので、変えたい場合はwink.ui.layout.Scroller.Scrollbar._initDom()の下記部分です。

scroller.js:1372

        if (this._direction == 'y') {
            st.top = "0px";
            st.right = "1px";
        } else {
            st.bottom = "2px";
            st.left = "0px";
        }

条件分岐で真判定の場合が縦用、逆に偽の場合が横用です。
CSSの設定なので見たままです。ここに変数を設置して、設置時に指定できるようにするのもいいかもしれません。

スクロールの跳ね返り調整

いわゆる、びよーんってやつですね。画面の端までいってさらにスクロールさせようとするとはねっかえるやつ。
wink.ui.layout.Scroller._slideTo()の下記部分を修正します。

scroller.js:1024

        if (btb) {
            d = "350ms";
            tr = "cubic-bezier(0.3, 0.1, 1.0, 0.5)";
        }

変数dがタップホールド(ドラッグ)をやめてから跳ね返りが完了するまでの時間です。CSS3のtransition-durationに指定する値に該当します。
trは加速度係数です。cubic-bezierなどCSS3のtransition-timing-functionに指定する値に該当します。

ちなみに俺が社内で「iPhoneネイティブと同じ感じにしてくれ」という要求をクリアした時の設定は下記のような感じでした。
あくまで社内的な判定なので実際の設定値とは異なると思います。

scroller.js:1024

        if (btb) {
            d = "400ms";
            tr = "cubic-bezier(0.25, 1, 1, 1)";
        }

端の引っ張り摩擦係数

前項に関連して、跳ね返る前のびよーんってなる伸び具合の設定。
wink.ui.layout.Scroller._handleMovementChanged()の下記変数で調整できます。

scroller.js:773

var boundFriction = 3;

デフォルトは3ですが、小さくするともっと伸びやすくなり、大きくすると伸びにくくなります。小数でも大丈夫です。

最初にスクロールバーを表示させない

設置したときや、updateSize()を実行したときに一瞬スクロールバーが表示されてからフェードアウトします。
これをさせたくない場合はwink.ui.layout.Scroller.Scrollbar._initDom()に以下のように追記します。

scroller.js:1359

    _initDom: function()
    {
        var dn = this._domNode = document.createElement('div');
        var cn = this._canvasNode = document.createElement('canvas');
        this._ctx = cn.getContext('2d');
        dn.appendChild(cn);

        cn.style.opacity = 0;       //追記
        this._view.showed = false;  //追記
        this._firstHide = false;    //追記

        var st = {
            position: "absolute",
            "pointer-events": "none",
            opacity: 1
        };

処理落ちなどでのぶっ飛び防止

時々処理落ちなどでtouchmoveイベントの値が偉いことになって、スクロールがぶっ飛ぶことがあります。
それを防止する為に最大速を設定することができます。
修正箇所は依存ライブラリのwink.ux.Inertia._computeInertia()になります。

inertia.j:132

        movement.directionX = significantMovementX.direction;
        movement.directionY = significantMovementY.direction;

//      movement.speedX = movement.dx / movement.dtx;
//      movement.speedY = movement.dy / movement.dty;
        movement.speedX = Math.min(movement.dx / movement.dtx, 4); //修正後:横用
        movement.speedY = Math.min(movement.dy / movement.dty, 4); //修正後:縦用

        wink.publish(this._EVENT_INERTIA_COMPUTED, {
            publisher: this,
            movement: movement,
            uxEvent: publishedInfos.uxEvent,
            target: publishedInfos.target
        });

速度を最大値4に制限しています。ここは適当に調整してください。

フォーム要素にフォーカスが当たるようにする

スクローラーが効いている範囲内ではタッチイベントがpreventDefault()されてしまって、内包しているフォーム要素にフォーカスが当たらなくなってしまいます。
それを解消するにはwink.ui.layout.Scroller_handleTouchNotTracked()に下記のif文を追記します。

scroller.js:646

        if (this._activated == false) {
            return;
        }

        if (!wink.isSet(this._selectionEvent)) { //追記した条件分岐
            uxEvent.preventDefault();
        }

        uxEvent.stopPropagation();

上記の修正により、2重でクリックイベントが発行されてしまう恐れがあるので、やや下にある下記部分をコメントアウトします。

scroller.js:671

        else if (uxEvent.type == "end")
        {
            this._backToBounds();
            this._hideScrollbars();
            if (wink.isSet(this._selectionEvent))
            {
                if (wink.isSet(this._callbacks.scrollerClicked))
                {
                    wink.call(this._callbacks.scrollerClicked, { uxEvent: uxEvent });
                }
                //this._handleSelection(uxEvent);
            }
        }

以上!

  • このエントリーをはてなブックマークに追加

SNSでもご購読できます。




コメントを残す