好的,我会尽力解释我正在努力做的事情。
使用 Webkit-overflow-scrolling 我正在创建一个具有可堆叠标题的列表,就像 iPhone 的联系人应用程序提供的效果一样。例如,“A”一直停留在顶部,直到“B”将其移开等。这在桌面上或用户仍在滚动时相对容易做到。
但是,一旦用户轻弹滚动条,它就会以缓慢的减速自行滚动,在此期间不会触发任何事件,直到滚动条完全停止,那时为时已晚。
经过大量研究,我发现轻弹减速持续时间始终相同(约 2.4 秒),只是结束位置发生了变化。我还可以看到很多人通过创建自己的库来模仿 iOS 行为来解决这个问题,这可能是我唯一的选择。
我正在尝试通过获取以下内容来计算元素的滚动顶部,因为它会自行滚动:
- 触摸起始位置
- 触摸结束位置
- 这两个手势的时间差
这应该允许我在它发生之前跟踪位置和最终结果。但是,我对如何正确使用这些信息来获得所需的结果有点困惑。任何信息或指针都会非常有帮助。
编辑
在被物理学困住后,我在Physics stackexchange上提问并收到了这个答案
因此我相信这段代码应该可以工作。我想检查以确保我对其应用了正确的逻辑
var timeStart = new Date().getTime(); //Triggered on a touchstart event
var timeEnd = new Date.getTime(); //Triggered on a touchend event
var startY = event.originalEvent.targetTouches.pageY //Pulled in from different functions containing the events
var endY = event.originalEvent.changeTouches[0].pageY //The where the touch starts and ends in px
var timeElasped = timeEnd - timeStart;
var distance = startY - endY;
var velocity = distance/timeElasped;
var result = velocity * (timeElasped - (1/4.8)*(timeElasped*timeElasped))
因此,结果应该等于触发最终滚动事件时 scrollTop 产生的结果。
编辑 2
可悲的是似乎不起作用。因此,我一定不能给出正确信息的公式。
不确定它是我正在接受的位置还是我如何执行公式。
编辑 3
我认为滚动速度确实每 325 毫秒降低 0.95 倍。我从这篇有用的文章中找到了这些信息。
这一观察使我相信动量滚动是一种指数衰减。它的特点是衰减的速度。有两种不同的表达方式:半衰期(还记得放射性衰变吗?)或时间常数。对于后者,它与一阶系统的阶跃响应非常相关。换句话说,减速系统只是一个过阻尼弹簧质量系统。事实证明,一切仍然基于物理学。
amplitude = initialVelocity * scaleFactor;
step = 0;
ticker = setInterval(function() {
var delta = amplitude / timeConstant;
position += delta;
amplitude -= delta;
step += 1;
if (step > 6 * timeConstant) {
clearInterval(ticker);
}
}, updateInterval);
事实上,这就是在 Apple 自己的 PastryKit 库(现在是 iAd 的一部分)中实现减速的方式。对于每个动画节拍,它会将滚动速度降低 0.95 倍(16.7 毫秒,目标为 60 fps)。这对应于 325 毫秒的时间常数。如果你是一个数学极客,那么显然你会意识到滚动速度的指数性质将产生位置的指数衰减。通过一点点涂鸦,最终你会发现 325 是 -16.7 / ln(0.95)。
这个谷歌文档应该显示公式,希望我做得对。左边是标准公式。在右侧,我试图将速度降低 0.95(速度*0.95)。我从测试中添加了真实信息,以显示我遇到的问题。如果所有方程都正确并且逻辑正确,那么它一定是输入的数据。
编辑 4
经过许多痛苦的小时后,我得出结论,这是 Safari 移动版 webkit 中的一个错误。最好的选择是使用 JS 库来模拟效果并等到错误修复。
- 停止所花费的时间总是变化的主要原因,因此太多的变量会改变以获得准确的读数。