最近Android、iOS両対応のスマフォ用JS開発をしていて、ページの部分縦スクロールにWink toolkitというライブラリを使用しました。
そこで、付属のスクローラー(wink.ui.layout.Scroller)の不具合解消やチューニングについてまとめます。
スクロールバーの長さと移動範囲の改善
上記デモサイトでは一見普通の動きをしていますが、スクロールする内容物の高さをある程度まで短くすると、スクロールバーの表示がおかしくなります。
試しにサンプルデモ(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);
}
}
以上!
コメント