如何计算滚动事件的滚动动量?
据我所知,在结尾滚动的开头必须有两个时间戳。还必须有一个“轴变化”变量,它基本上是无惯性滚动的量。
这是我当前负责结束滚动的代码:
if ((type == kMXTEnd || type == kMXTMovedOut) && _isScrolling)
{
long int finishTime = MXTimestamp();
printf("SCEnd: Ending scroll at %ld\n",finishTime-_beginTime);
/* scrollX is the change in X axis */
/* finishTime is time from touch down to touch up */
printf(" * Time: %ld ChangeX: %f\n",finishTime,scrollX);
_isScrolling = FALSE;
_originalScrollPoint = _scrollPoint;
}
是否有可能为此计算“惯性加法”?就像惯性所获得的额外偏移量一样,除了主要滚动值之外我还可以滚动。或者我需要获得其他变量吗?
我需要这个,因为我正在编写自己的UI工具包,它实际上并不基于任何东西。
答案 0 :(得分:5)
您可以使用“最近的轴更改”队列来模拟此情况。
如果您使用相应的时间戳存储说明最后半秒的更改,则可以测试队列是否长于值N
(即,如果用户拖动它比平时更快) 。你知道最后半秒的时间,也就是你可以获得速度的时间。
将速度缩放到合理的位置(比如说...对于15px / .5秒,映射到~25px / sec)并应用负加速度(也适用于上面的例子,比如-20px / sec),每两次毫秒(或者你的系统可以轻松处理它的速度快,不要用它来过度压缩它。)
然后运行计时器,更新每个刻度(speed+=accel*time_scale
)的速度,然后更新位置(position+=speed*time_scale
)。当速度达到0(或低于它)时,杀死计时器。
答案 1 :(得分:5)
我所取得的成绩如下:
在每个鼠标拖动事件(或触摸事件)上,存储速度(因此移动量除以自上一帧以来的时间)和时间戳。你只需要最后一个,所以这只是两个变量。
当释放鼠标/触摸时,检查上一个时间戳是否足够近(我使用0.3秒)。如果是这样,将变量inertialVelocity设置为最后计算的速度;否则将其设置为0以防止在用户仔细选择位置时滚动。
然后在每次更新时(通过计时器或每个渲染调用,取决于你如何渲染),滚动惯性速度* INERTIA_SCROLL_FACTOR(我使用0.9)并将惯性速度乘以INERTIA_ACCELERATION(我使用0.98)。
您可能想要添加一个阈值,因此如果inertialVelocity变得太小,滚动就会停止。我使用1作为阈值,因为我的渲染库使用浮点数作为坐标。如果坐标是积分,它将自己降为零。
要记住的一点是,惯性速度可以是正的也可以是负的,具体取决于方向。
所以,在伪代码中:
OnMouseMove:
inertialVelocity = moveDistance / (now - timeOfLastEvent)
timeOfLastEvent = now
OnMouseUp:
if (now - timeSinceLastEvent > 0.3f)
inertialVelocity = 0
OnTimer/OnRender:
// timeDelta is needed only when doing this on render events, just to make
// it independent of the render speed. It is the time since the previous render
scrollPosition += inertialVelocity * INERTIA_SCROLL_FACTOR * timeDelta
inertialVelocity *= INERTIA_ACCELERATION * timeDelta
// Keep in mind that velocity can be negative as well, hence the abs
if (abs(inertialVelocity) < INERTIA_THRESHOLD)
inertialVelocity = 0