如何计算滚动动量滚动事件?
我明白在滚动的开始和结束处必须有两个时间戳。还必须有一个"轴变化"变量,它基本上是滚动量,没有惯性。
这是我目前负责滚动结束的代码:
if ((type == kMXTEnd || type == kMXTMovedOut) && _isScrolling)
{
long int finishTime = MXTimestamp();
printf("SCEnd: Ending scroll at %ldn",finishTime-_beginTime);
/* scrollX is the change in X axis */
/* finishTime is time from touch down to touch up */
printf(" * Time: %ld ChangeX: %fn",finishTime,scrollX);
_isScrolling = FALSE;
_originalScrollPoint = _scrollPoint;
}
是否有可能计算出"惯性加法"?就像通过惯性获得的额外偏移量,我可以在主要滚动值之外滚动。还是需要额外的变量?
我需要这个,因为我正在编写自己的UI工具包,它并不是真正基于任何东西。
我所做的取得好成绩的方法如下:
在每个鼠标拖动事件(或触摸事件)上,存储速度(即移动量除以上一帧以来的时间)和时间戳。您只需要最后一个,所以只有两个变量。
当鼠标/触摸被释放时,检查最后一个时间戳是否足够近(我使用0.3秒)。如果是,设置一个变量intialvelocity为最后计算的速度;否则将其设置为0,以防止用户仔细选择位置时滚动。
然后在每次更新(无论是通过计时器,或每个渲染调用,取决于你是如何渲染),滚动由惯性速度*惯性tia_scroll_factor(我使用0.9)和乘以惯性速度惯性加速度(我使用0.98)
你可能想要添加一个阈值,所以滚动停止,如果惯性速度变得太小。我使用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
您可以用"最近的轴更改"队列来模拟这一点。
如果你用相应的时间戳存储最后半秒的变化,那么你可以测试队列是否长于一个值N
(即用户是否比通常更快地拖到最后)。你知道在最后半秒内走过的总距离,时间,从这些你可以得到速度。
将速度调整到合理的水平(比如…)15像素/。5秒,映射到~25px/秒),并应用负加速度(也适当缩放,对于上面的例子,说-20px/秒)每几毫秒(或尽可能快,你的系统可以轻松处理它,不要过度强调它)。
然后运行计时器,在每个刻度处更新速度(speed+=accel*time_scale
),然后是位置(position+=speed*time_scale
)。当速度达到0(或低于0)时终止定时器