5

モバイル Web アプリに単純なカスタム スクロール メソッドを実装しようとしています。ページが「フリック」された場合に少し勢いのある効果が欲しい縦スクロールに問題があります。

問題は、ドラッグジェスチャの後に「フリック」ジェスチャ (そのジェスチャの速度とおそらく長さ) を検出し、方向を変更することです。私の言いたいことを理解していただければ幸いです。ページを上下にドラッグできます。そのドラッグの最後に、フリックもあるかどうかを検出したいと思います..

2つをどのように分離しますか?そのようなロジックはどのように見えますか?

助けてくれてありがとう。

コード: (この抜粋が少しごちゃごちゃしていたらごめんなさい)

 var Device = function() {

    //define some private variablees
    var startY,
        startX,
        startTime,
        deltaY = 0,
        deltaX = 0,
        lastY,
        currentPage,
        nextPage,
        prevPage,
        directionY,
        lastTime,
        pages,
        pane,
        offsetX = 0,
        offsetY = 0,
        isPanning,
        isScrolling,
        isTouch = "ontouchstart" in window;


    return {



        init: function() {

        document.getElementById('frame').addEventListener(isTouch ? 'touchstart' : 'mousedown', Device.onTouchStart, false);


            //get all panes in an array
            panes = document.querySelectorAll('.pane');


        },     

onTouchStart: function (evt) {

            //get X and Y of the touch event
            var touch = isTouch ? event.touches[0] : event;
            startY = touch.clientY;

            //add listener for touch move and end
            document.addEventListener(isTouch ? 'touchmove' : 'mousemove', Device.onTouchMove, false);
            document.addEventListener(isTouch ? 'touchend' : 'mouseup', Device.onTouchEnd, false);

            startTime = new Date();
        },
        onTouchMove: function (evt) {

                //get X and Y of the touch event
                var touch = isTouch ? event.touches[0] : event;

                currentY = touch.clientY;

                //calc touch length
                deltaY = currentY - startY;             


                //Detect if scroll is bigger than threshold 5px
                 if (Math.abs(deltaY) > 5 && !isPanning) {



                        isScrolling = true;


                        //get the element
                           pane = panes[0];

                        //set new position
                        offsetY = pane.lastOffset + deltaY;

                                                    //call animation
                        Device.scrollTo(pane,0,offsetY);

                    }

            //detect last direction     
             directionY = (lastY >= currentY) ? 1 : 0;


                //roll over last variables  
                lastY = currentY;
                lastTime = new Date();
        },

        onTouchEnd: function () {

        //timing
                var endTime = new Date();
                var velocity = (endTime - lastTime).toFixed(0);


            console.log('velocity: ' + velocity);

//TEMPORARY
pane.lastOffset = offsetY;


                isScrolling = false;

                //housekeeping
                document.removeEventListener(isTouch ? 'touchmove' : 'mousemove', Device.onTouchMove, false);
                document.removeEventListener(isTouch ? 'touchend' : 'mouseup', Device.onTouchEnd, false);

           //call for momentum  
           Device.doMomentum(velocity);

        },
        scrollTo: function(el,x,y) {
        if (el) {

                el.style['-webkit-transition-timing-function'] = '';
                el.style['-webkit-transition-duration'] = '0ms';
                el.style[ 'WebkitTransform' ] = 'translate3d('+x+'px,'+y+'px, 0px)';
        }
        },
        animateTo: function(el,x,y) {
        if (el) {
                el.style['-webkit-transition-timing-function'] = 'cubic-bezier(0,0,0.25,1)';
                el.style['-webkit-transition-duration'] = '300ms';
                el.style[ 'WebkitTransform' ] = 'translate3d('+x+'px,'+y+'px, 0px)';
        }
        },
        doMomentum: function(velocity) {



        console.log((directionY == 1) ? 'up': 'down');
        console.log('pane.lastOffset: ' + pane.lastOffset);
        var endPosition;

            if (directionY == 1) {
         endPosition = pane.lastOffset - velocity;

        } else {

         endPosition = parseFloat(pane.lastOffset) + parseFloat(velocity);
        }

        console.log(endPosition);

        Device.animateTo(pane,0,endPosition);

        pane.lastOffset = endPosition;


        }
4

2 に答える 2

2

フリックは、位置と時間に関連付けられた複数のポイントを使用して検出されると思います。通常のドラッグの動きについて考えると、かなり一定の速度で行われます。ただし、最後のフリックの速度は、残りのドラッグよりも大幅に高くする必要があります。

したがって、約 0.1 秒間隔のドラッグ ポイント サンプルを含む 5 ポイントの配列がある場合 (および古い値が配列内で前にある場合)、通常のドラッグの速度をそのように計算できます (垂直方向のドラッグの場合)。

var dragVelY = (samples[2].y - samples[0].y)/3;

次に、潜在的なフリックの速度は次のようになります。

var flickVelY = (samples[4].y-samples[2].y)/3;

flickVelY が dragVelY よりも大幅に大きい場合は、フリックが検出されています。私はこれをテストしていないので、適切なドラッグまたはフリック速度を得るには、配列内のサンプル数と比較するサンプル数を調整する必要があるかもしれません。ドラッグが長い場合は、Array.shift メソッドと Array.push メソッドを使用して、サンプル配列から古い位置を移動し、最後に新しい位置をプッシュします。

于 2012-06-08T01:02:04.100 に答える
0

参考までに、私がやったのは、-イベントと-イベントの間に経過した時間を単純に使用することonTouchMoveでしonTouchEndた。

基本的に、onTouchMoveコールバックで継続的に上書きされる日付変数があります。

onTouchMove: function (evt) {
   ...
 intermediateTime = new Date();
   ...
}

そしてonTouchEndendTime 値を取得し、差を評価します。この時間が非常に短い場合、最後に「フリック」があったと思います。

onTouchEnd: function (evt) {
   ...
 var endTime = new Date();

 var vel  = (endTime - intermediateTime);

 if (vel <= 100) {

    doMomentumOrSomething();

 }
   ...
}

これは非常に単純ですが、実際にはかなりうまく機能します。

于 2012-06-08T12:40:49.687 に答える