实现动态滚动的算法

发布于 2024-08-12 10:45:40 字数 94 浏览 3 评论 0原文

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

What are some good algorithms for creating a kinetic scrolling implementation? The feature would be tested on a custom UI list. While I am targeting mobile devices (those that do not have this feature built-in), any algorithm or code example from different programming field may also suit.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

冬天旳寂寞 2024-08-19 10:45:40

自从最初提出这个问题以来,我仔细阅读了 Pastrykit 的源代码,苹果在这个框架中精确地复制了 JavaScript 中的动态滚动。不存在粒子物理循环——触摸的速度是在手指抬起的那一刻测量的。从那时起,滚动使用简单的缓动函数进行动画处理,该函数使用速度作为输入参数。

Since this was originally asked, I have since carefully read the source code for pastrykit, the framework in which apple has exactly duplicated their kinetic scrolling in javascript. There is no particle physics loop- The velocity of the touch is measured at the exact moment that the finger is lifted. From that point forward, the scroll is animated using a simple easing function that uses the velocity as an input parameter.

兮子 2024-08-19 10:45:40

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

  1. 您需要测量光标(鼠标光标或手指)的速度
  2. 实现一个简单的粒子物理循环。有关如何执行此操作的信息可以在此处
  3. 找到您的粒子“边界”使用从滚动平面的宽度和视口的宽度
  4. 连续导出的数学将鼠标速度和粒子速度之间的差值添加到粒子的速度中,因此粒子的速度“匹配”鼠标的速度为只要它在移动。
  5. 用户一抬起手指就停止执行步骤 4。物理循环负责惯性。
  6. 添加您的个人特色,例如“缓冲”边距,以及根据芝诺悖论计算运动的平滑滚动“锚点”。
  7. 我差点忘了:采用上面导出的坐标,并将其用作滚动平面的位置。

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

编辑:更改了链接。抱歉,指向了稍微错误的页面。编辑2:还是不?无论如何,我链接到的原始页面是当前链接页面上的第一个链接。

I implemented one myself recently. These are the steps I took.

  1. You need to measure the velocity of your cursor (either mouse cursor or finger)
  2. Implement a simple particle physics loop. Information about how to do that can be found here
  3. give your particle "bounds" using math derived from the width of your scrolling plane, and the width of your viewport
  4. continuously Add the the difference between the mouse velocity and the particle velocity, to the particle's velocity, so the particle's velocity "matches" the mouse's velocity for as long as it's moving.
  5. Stop doing step 4 as soon as the user lifts their finger. The physics loop takes care of inertia.
  6. Add your personal flourishes such as "bumper" margins, and smooth scrolling "anchor" points that operate on zeno's paradox for calculating motion.
  7. I nearly forgot: Take the coordinates derived from above, and use it as the location of your scrolling plane.

I will probably open source this code soon. How soon do you need this?

edit:changed the link. Sorry, pointed to slightly the wrong page. edit2: or not? Anyway, original page I linked to was first link on currently linked page.

迷鸟归林 2024-08-19 10:45:40

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

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

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

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

  3. 灵活的滚动限制:当滚动到达末尾时,我希望小部件滚动一些,但提供阻力,而不是突然停止。为此,我将两端允许的滚动范围扩展了一定量,该量是我定义为小部件尺寸的函数。我发现在每一端添加一半的宽度或高度效果很好。给滚动带来某种阻力的感觉的技巧是当滚动位置超出范围时调整显示的滚动位置。为此,我使用了缩小加减速函数(这里有一些很好的缓动函数此处)。< /p>

  4. Spring 行为:由于现在可以滚动超过有效范围,因此如果用户将其超出范围,我需要一种方法将滚动条带回有效位置。这是通过当滚动条停在超出范围的位置时调整滚动偏移量来实现的。我发现可以提供漂亮的弹性外观的调整功能是将当前位置到所需位置的距离除以一个常数,然后将偏移量移动该量。常数越大,运动越慢。

  5. 滚动条:最后一步是添加覆盖滚动条,滚动条在滚动开始时淡入,在滚动结束时淡出。

I just added a scroller widget to my mobile GUI framework, so I thought I'd share my solution here.

Since this is a pretty complex issue, I decided to divide it up into smaller somewhat independent subtasks, as follows:

  1. Basic scrolling functionality: this task consisted in handling drag events in the simplest way, which is by scrolling the contents according to the drag distance and direction. This was relatively straightforward to implement, the only tricky aspect was to know when to start a drag operation vs. when to pass down a tap event to a child widget inside the scrollable area.

  2. Scroll inertia: this one was the most challenging. The idea here is that scrolling should continue for some time after the user lifts the finger, slowing down until it stops completely. For this I needed to have an idea of the scroll velocity. Unfortunately it is not accurate to compute the velocity from a single sample, so while the user is scrolling I record the last N motion events in a circular buffer, along with the time at which each event occurred. I found N=4 to work just fine on the iPhone and on the HP TouchPad. When the finger is lifted I can compute an approximate start velocity for the inertial scrolling from the recorded motion. I defined a negative acceleration coefficient and used standard motion formulas (see here) to let the scrolling die down nicely. If the scroll position reaches a border while still in motion I just reset the velocity to 0 to prevent it from going out of range (the abrupt stop is addressed next).

  3. Flexible scrolling limits: instead of going into an abrupt stop when the scroll reaches the end I wanted the widget to scroll some, but offering resistance. For this I extended the allowed scroll range on both ends by an amount that I defined as a function of the widget dimensions. I've found that adding half the width or height on each end worked nicely. The trick to give the scrolling the feeling that it is offering some resistance was to adjust the displayed scroll positions when they are out of range. I used a scaling down plus a deceleration function for this (there are some good easing functions here).

  4. Spring behavior: since now it is possible to scroll past the valid range, I needed a way to bring the scroller back to a valid position if the user left it out of range. This is achieved by adjusting the scroll offset when the scroller comes to a stop at an out of range position. The adjustment function that I've found to give a nice springy look was to divide the distance from the current position to the desired position by a constant and moving the offset by that amount. The bigger the constant the slower motion.

  5. Scrollbars: the final touch was to add overlay scrollbars, which fade in when scrolling starts and fade out when it ends.

不再见 2024-08-19 10:45:40

你看过 Robert Penner 的缓动函数吗?

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

IIRC 这些最初是针对 Actionscript 的,并且已经存在许久。

Have you looked at Robert Penner's easing functions?

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

IIRC these were originally for Actionscript and have been around for a long time.

看春风乍起 2024-08-19 10:45:40

我搜索了很多。将它们结合在一起我提出了我的解决方案。

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

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

I searched a lot. Combined it all together i made my solution.

  1. While pointer down you should calculate difference in pixels btw each call onTouchMove handler. On touch end save this value in some variable, lets call it diffPx for example.
  2. Use requestAnimationFrame for continious momentum scrolling. On each frame scroll your container by diffPx =* 0.95 as long as diffPx would not reach some limit value(I used 0.25).
  3. One important limitation. Do step 2 only if diffPx on pointer up more than limit value(I used 5px).

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

锦上情书 2024-08-19 10:45:40

好吧,我认为这会是这样的:a)获取用户滚动速度的速度b)当他离开手指时,自动滚动列表,但速度随着用户的初始速度而减小。

Well i think it would be something like a) get velocity of how fast user scrolled b) when he leaves his finger, auto scroll the list but with a decreasing velocity with an initial velocity of what the user had.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文