实现动态滚动的算法

27

有哪些适用于创建动态滑动实现的好算法?该功能将在自定义UI列表上进行测试。虽然我针对的是没有此功能内置的移动设备,但来自不同编程领域的任何算法或代码示例也可能适用。

6个回答

28
自从最初被问及以来,我已经仔细阅读了pastrykit的源代码,这是苹果用javascript精确复制他们的动力滚动所采用的框架。没有粒子物理循环 - 触摸速度是在手指离开时精确测量的。从那时起,滚动使用一个简单的缓动函数作为输入参数,使用速度进行动画处理。

26

我最近自己实现了一个。以下是我采取的步骤。

  1. 你需要测量你的光标速度(无论是鼠标光标还是手指)。
  2. 实现简单的粒子物理循环。如何实现可以在此处找到相关信息。
  3. 使用从滚动平面宽度和视口宽度派生出的数学方法为粒子设定“边界”。
  4. 持续添加鼠标速度与粒子速度之间的差值到粒子速度上,以便在移动时粒子速度与鼠标速度相匹配。
  5. 一旦用户松开手指,立即停止执行第四步。物理循环会处理惯性问题。
  6. 添加你个人的装饰,例如“缓冲区”边距和基于Zeno悖论计算运动的平滑滚动“锚点”。
  7. 几乎忘记了:使用上述得出的坐标作为你的滚动平面位置。

我可能很快就会开源这段代码。你需要多快?

编辑:更改了链接。抱歉,链接了错误的页面。编辑2:还是没有?不管怎样,我链接的原始页面是当前链接页面上的第一个链接。


2
我会在几周内尝试自行实现这个。现在我只是在考虑它。感谢您的回复。如果您决定开源您的解决方案,请在此发布一些公告。 - Bojan Milankovic
3
很抱歉,由于我只是一个语言模型,无法访问因链接失效而无法查看的内容。 - iCollect.it Ltd

16

我刚刚在我的移动GUI框架中添加了一个滚动小部件,所以我想在这里分享我的解决方案。

由于这是一个相当复杂的问题,我决定将其分成更小的相对独立的子任务,如下所示:

  1. 基本滚动功能:此任务包括以最简单的方式处理拖动事件,即根据拖动距离和方向滚动内容。这相对容易实现,唯一棘手的问题是知道何时开始拖动操作,而不是将轻点事件传递给可滚动区域内的子小部件。

  2. 滚动惯性:这是最具挑战性的任务。这里的想法是,在用户抬起手指后,滚动应该继续一段时间,直到完全停止。为此,我需要了解滚动速度的概念。不幸的是,从单个样本计算速度并不准确,因此当用户滚动时,我会在循环缓冲区中记录最近的N个运动事件,以及每个事件发生的时间。我发现N = 4在iPhone和HP TouchPad上都可以很好地工作。当手指抬起时,我可以根据记录的动作计算出惯性滚动的大致起始速度。我定义了一个负加速系数,并使用标准运动公式(见这里)使滚动平稳地消失。如果滚动位置在运动中仍然到达边界,我只需将速度重置为0,以防止其超出范围(下一个处理突然停止的问题)。

  3. 灵活的滚动限制:在滚动到底部时,组件不会突然停止,而是会滚动一段距离并提供阻力。为此,我扩展了两端允许滚动的范围,其大小是根据组件尺寸定义的函数。我发现,在每端添加宽度或高度的一半效果很好。给滚动提供一些阻力的技巧是当滚动位置超出范围时调整显示的滚动位置。我使用了缩放和减速函数来实现这一点(这里有一些好的缓动函数链接)。

  4. 弹性行为:由于现在可以滚动到有效范围之外,我需要一种方法来将滚动条带回有效位置,如果用户将其留在范围之外。当滚动条停在超出范围的位置时,通过调整滚动偏移量来实现。我发现,将当前位置到期望位置的距离除以一个常数,并将偏移量移动该数量,可以产生不错的弹性效果。常数越大,运动越慢。

  5. 滚动条:最后的点睛之笔是添加浮层滚动条,当开始滚动时淡入,结束时淡出。


3

你看过罗伯特·彭纳的缓动函数了吗?

http://www.robertpenner.com/easing/

据我所知,这些最初是为Actionscript设计的,并且已经存在很长时间了。


1
我以前从未见过这些!非常有用。+1 - Mapsy

1

我进行了大量的搜索。将它们组合在一起,我制定了我的解决方案。

  1. 当指针按下时,您应该计算每次onTouchMove处理程序调用之间的像素差异。在触摸结束时,将此值保存在某个变量中,例如称为diffPx
  2. 使用requestAnimationFrame进行连续的动量滚动。在每帧上,将您的容器滚动diffPx *= 0.95,只要diffPx不会达到某个限制值(我使用的是0.25)。
  3. 一个重要的限制。仅当指针抬起时的diffPx 大于限制值(我使用的是5px)时才执行步骤2。

https://developer.mozilla.org/ru/docs/Web/API/window/requestAnimationFrame


0

我认为这个问题可以这样解决:a) 获取用户滚动的速度 b) 当用户松开手指时,在保持初始速度的情况下减慢自动滚动。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接