【发布时间】:2011-04-12 19:05:48
【问题描述】:
我知道如何在 UIScrollView 的移动中获取 contentOffset,有人可以向我解释一下如何获得一个实际数字来表示 UIScrollView 在跟踪或减速时的当前速度吗?
【问题讨论】:
-
没什么大不了的,但我把这个非常古老的问题的现代解决方案放在了底部。
标签: iphone scroll uiscrollview
我知道如何在 UIScrollView 的移动中获取 contentOffset,有人可以向我解释一下如何获得一个实际数字来表示 UIScrollView 在跟踪或减速时的当前速度吗?
【问题讨论】:
标签: iphone scroll uiscrollview
你可以查看PageControl 示例代码,了解如何获取scrollview 的contentOffset。
contentOffset on 运动可以从UIScrollViewDelegate 方法中获得,命名为- (void)scrollViewDidScroll:(UIScrollView *)scrollView,通过查询scrollView.contentOffset。当前速度可以通过 delta_offset 和 delta_time 计算出来。
【讨论】:
在你的 UIScrollViewDelegate 上有这些属性
CGPoint lastOffset;
NSTimeInterval lastOffsetCapture;
BOOL isScrollingFast;
然后为您的 scrollViewDidScroll 编写此代码:
- (void) scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint currentOffset = scrollView.contentOffset;
NSTimeInterval currentTime = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval timeDiff = currentTime - lastOffsetCapture;
if(timeDiff > 0.1) {
CGFloat distance = currentOffset.y - lastOffset.y;
//The multiply by 10, / 1000 isn't really necessary.......
CGFloat scrollSpeedNotAbs = (distance * 10) / 1000; //in pixels per millisecond
CGFloat scrollSpeed = fabsf(scrollSpeedNotAbs);
if (scrollSpeed > 0.5) {
isScrollingFast = YES;
NSLog(@"Fast");
} else {
isScrollingFast = NO;
NSLog(@"Slow");
}
lastOffset = currentOffset;
lastOffsetCapture = currentTime;
}
}
从这里我得到每毫秒的像素,如果大于 0.5,我记录得很快,而下面的任何东西都记录得很慢。
我用它来加载动画表格视图上的一些单元格。如果我在用户快速滚动时加载它们,它的滚动效果不会很好。
【讨论】:
captureInterval const 并在计算 scrollSpeedNotAbs 时使用它来增加算法的可读性(作为大脑停在* 10,因为速度的一般公式是距离/时间)。
有一个更简单的方法:检查 UISCrollview 的平移手势识别器。有了它,你可以得到这样的速度:
CGPoint scrollVelocity = [[_scrollView panGestureRecognizer] velocityInView:self];
【讨论】:
scrollVelocity 将在用户抬起手指后立即变为 0.0f(因为这会结束平移手势)。所以这是在拖动滚动视图时测量速度的好方法,但如果轻弹则不起作用。
scrollViewWillEndDragging:withVelocity:targetContentOffset: 来处理当前触摸事件结束后的速度或偏移条件
对于简单的速度计算(所有其他答案都比较复杂):
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat scrollSpeed = scrollView.contentOffset.y - previousScrollViewYOffset;
previousTableViewYOffset = scrollView.contentOffset.y;
}
【讨论】:
这可能会有所帮助
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
【讨论】:
(0.0,-5.35356)。按 y 轴滚动,5.35.. -> 每次scrollViewDidScroll 调用 15 个点 :) 所以,5 非常快。
将@bandejapaisa 转换为 Swift 5 的答案:
UIScrollViewDelegate 使用的属性:
var lastOffset: CGPoint = .zero
var lastOffsetCapture: TimeInterval = .zero
var isScrollingFast: Bool = false
还有scrollViewDidScroll函数:
func scrollViewDidScroll(scrollView: UIScrollView) {
let currentOffset = scrollView.contentOffset
let currentTime = Date.timeIntervalSinceReferenceDate
let timeDiff = currentTime - lastOffsetCapture
let captureInterval = 0.1
if timeDiff > captureInterval {
let distance = currentOffset.y - lastOffset.y // calc distance
let scrollSpeedNotAbs = (distance * 10) / 1000 // pixels per ms*10
let scrollSpeed = fabsf(Float(scrollSpeedNotAbs)) // absolute value
if scrollSpeed > 0.5 {
isScrollingFast = true
print("Fast")
} else {
isScrollingFast = false
print("Slow")
}
lastOffset = currentOffset
lastOffsetCapture = currentTime
}
}
【讨论】:
这是在 SWIFT 中执行此操作的另一种聪明方法:-
func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
if velocity.y > 1.0 || velocity.y < -1.0 && self.sendMessageView.isFirstResponder() {
// Somthing you want to do when scrollin fast.
// Generally fast Vertical scrolling.
}
}
所以如果你垂直滚动你应该使用velocity.y,如果你水平滚动你应该使用velocity.x。一般如果 value 大于 1 且小于 -1,则一般表示快速滚动。因此,您可以根据需要更改速度。 +value 表示向上滚动,-value 表示向下滚动。
【讨论】:
So you can change the speed as you want 时说过。所以我想知道,你如何改变滚动的速度?
使用现代 Swift/iOS 很容易做到这一点:
var previousScrollMoment: Date = Date()
var previousScrollX: CGFloat = 0
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let d = Date()
let x = scrollView.contentOffset.x
let elapsed = Date().timeIntervalSince(previousScrollMoment)
let distance = (x - previousScrollX)
let velocity = (elapsed == 0) ? 0 : fabs(distance / CGFloat(elapsed))
previousScrollMoment = d
previousScrollX = x
print("vel \(velocity)")
当然你想要以每秒点数为单位的速度,就是这样。
人类的拖拽速度为 200 - 400 pps(在 2017 年的设备上)。
1000 - 3000 是快速投掷。
当它减速到停止时,20 - 30 是常见的。
你经常会看到这样的代码..
if velocity > 300 {
// the display is >skimming<
some_global_doNotMakeDatabaseCalls = true
some_global_doNotRenderDiagrams = true
}
else {
// we are not skimming, ok to do calculations
some_global_doNotMakeDatabaseCalls = false
some_global_doNotRenderDiagrams = false
}
这是在手机上“略读工程”的基础。 (这是一个大而困难的话题。)
请注意,这不是一个完整的略读解决方案;您还必须注意不寻常的情况,例如“它已停止”“屏幕刚刚关闭”等。
【讨论】: