5

我正在尝试在我的移动网络应用程序中实现一个简单的自定义滚动方法。我在垂直滚动时遇到问题,如果页面被“轻弹”,我希望有一点动量效果。

问题是在拖动手势之后检测“轻弹”手势(该手势的速度和可能长度),改变方向等等。希望你明白我的意思,你可以向上或向下拖动页面,在拖动结束时,我想检测是否还有轻弹..

你如何将两者分开?这样的逻辑看起来如何?

非常感谢您的帮助。

代码:(对不起,如果这段摘录有点乱)

 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

我认为可以使用与位置和时间相关的多个点来检测轻弹。如果您考虑正常阻力的运动,它将以相当恒定的速度完成。然而,最后的轻弹应该具有明显高于其余阻力的速度。

因此,如果您有一个 5 点数组,其中包含间隔约 0.1 秒的拖动点样本(并且较早的值在数组中较早),您可以像这样计算正常拖动的速度(对于垂直拖动)

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-event 和onTouchEnd-event 之间经过的时间。

onTouchMove基本上,我有一个在回调中不断覆盖自身的日期变量:

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

然后onTouchEnd我得到一个 endTime 值并评估差异。如果这个时间非常低,那么我认为最后有一个“轻弹”。

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

 var vel  = (endTime - intermediateTime);

 if (vel <= 100) {

    doMomentumOrSomething();

 }
   ...
}

这非常简单,但实际上效果很好。

于 2012-06-08T12:40:49.687 回答