UIScrollView减速后的静止偏移量预测

26

我希望能够预测UIScrollView在快速滑动手势后的最终停靠位置偏移量。它不需要像素级别的准确度,但足够接近以便用户感知不到差异(即它的移动量不会过多或过少)。

我知道有人会问:为什么要这样做呢?因为我在UIScrollView中有一个类似于表格视图的菜单控件。我想使其最上面的项完全显示,并与UIScrollView顶部齐平。UIScrollView的分页特性并不完全符合我的需求,因为强烈的滑动手势不能超过视图边界的倍数。

处理正常的触摸事件相当容易。在touchesEnded:withEvent:中,我可以滚动到最近的完整菜单项。难点在于减速。

有两个常量用于减速率:UIScrollViewDecelerationRateNormalUIScrollViewDecelerationRateFast。它们的值在iPhone OS 3.0中分别为0.998和0.990。我试图弄清楚苹果在减速时所使用的数学方法,但是一无所获。

如果我能够相当准确地预测出最终的停靠位置偏移量,那么在减速期间的早期阶段,我就可以简单地使用scrollRectToVisible:animated:来移动到一个与视图边界顶部齐平的偏移量。

有没有数学方面的人知道苹果在减速时可能所采用的方法?我是否应该收集大量的减速事件数据,绘制它们的图形,并得出一个接近的结果呢?


为什么你不能使用UITableView来完成这个任务? - nornagon
哦,我明白了——滚动结束时,您想捕捉到最近的菜单项? - nornagon
我要注意的是,像这样捕捉菜单项并不是标准的iOS行为——即使以这种微妙的方式打破用户期望的行为也可能会令人震惊。 - JonathonW
3个回答

16

控制UIScrollView的目标内容偏移量(iOS 5)

iOS 5中,UIScrollViewDelegate新增了一个方法:scrollViewWillEndDragging:withVelocity:targetContentOffset:

这正好符合你想要实现的功能。

当滚动视图的pagingEnabled属性设置为YES时,不会调用此方法。您的应用程序可以更改targetContentOffset参数的值,以调整scrollView完成其滚动动画的位置。

iOS4及以下版本的替代方案

UIScrollViewdecelerationRate更改为UIScrollViewDecelerationFast,然后在scrollViewDidEndDecelerating中移动到最接近的“页面”。

快速减速使得完全停止/滑动更加自然/不那么显眼。


1
顺便提一下,现在是2016年,即使将pagingEnabled设置为YES/true,方法scrollViewWillEndDragging:withVelocity:targetContentOffset:仍然会被调用。这对于确定用户在放开手指之后但橡皮筋动画完成之前将落在哪个页面上非常有用。 - pejalo

4

在UIScrollView减速时,您可以观察滚动速度,并在速度低于某个值时捕捉到最近的菜单项。

您可能需要实现UIScrollViewDelegate方法scrollViewDidEndDragging:willDecelerate:scrollViewDidScroll:。当用户松开手指完成滚动手势时,将调用scrollViewDidEndDragging:willDecelerate:。开始监视scrollViewDidScroll:事件,并观察UIScrollView当前位置与其先前位置之间的差异,除以时间差:

float velocity = (currentPosition - lastPosition) / (currentTime - lastTime);

当速度低于最小值时,调用UIScrollView上的scrollRectToVisible:animated:方法。

这大致是我最终做的,但我仍然对提前预测有兴趣。 - Steve Madsen
你是否有可能通过更早地预测来获得明显更好的结果? - nornagon
当然。我越早知道动画结束的位置,动画就会越流畅。考虑到:如果速度阈值为0,则必须加速(或反向)滚动运动以进行捕捉。随着阈值的增加,这种效果变得越来越不明显。 - Steve Madsen
如果你将阈值设得足够大,它仍然足够准确吗?如果不是,尝试使用二次而不是线性逼近来估计它。(即测量和预测加速度以及速度) - nornagon
@nornagon和Steve Madsen,你们能帮我解决一个类似的问题吗?http://stackoverflow.com/questions/16731569/uitableview-inside-a-uiscrollview-scrolling-issue - jonypz

0

我不能评论(我猜我需要50个声望),所以这不是一个完整的答案,但考虑到减速的0.998和0.990值,我的直觉是它们只是在每帧将当前速度乘以减速率。


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