【问题标题】:iPhone UIScrollView Speed CheckiPhone UIScrollView 速度检查
【发布时间】:2011-04-12 19:05:48
【问题描述】:

我知道如何在 UIScrollView 的移动中获取 contentOffset,有人可以向我解释一下如何获得一个实际数字来表示 UIScrollView 在跟踪或减速时的当前速度吗?

【问题讨论】:

  • 没什么大不了的,但我把这个非常古老的问题的现代解决方案放在了底部。

标签: iphone scroll uiscrollview


【解决方案1】:

你可以查看PageControl 示例代码,了解如何获取scrollview 的contentOffset。

contentOffset on 运动可以从UIScrollViewDelegate 方法中获得,命名为- (void)scrollViewDidScroll:(UIScrollView *)scrollView,通过查询scrollView.contentOffset。当前速度可以通过 delta_offset 和 delta_time 计算出来。

  • Delta_offset = current_offset - pre_offset;
  • Delta_time = current_time - pre_time;

【讨论】:

  • 哦,我猜到了使用距离随时间变化的实时速度
  • 当前时间可以通过QuartzCore框架中的CACurrentMediaTime()获取。然后你可以通过距离和时间计算速度。
【解决方案2】:

在你的 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,我记录得很快,而下面的任何东西都记录得很慢。

我用它来加载动画表格视图上的一些单元格。如果我在用户快速滚动时加载它们,它的滚动效果不会很好。

【讨论】:

  • 太棒了,这正是我的计划。
  • 感谢您提供了一个不错的解决方案,我唯一要更改的是将 0.1 替换为 captureInterval const 并在计算 scrollSpeedNotAbs 时使用它来增加算法的可读性(作为大脑停在* 10,因为速度的一般公式是距离/时间)。
  • scrollview / collectionView 的精彩扩展!拯救了我的一天:-)
  • 虽然这不是错误的,但我将这个非常古老的问题的现代解决方案放在了底部。干杯
【解决方案3】:

有一个更简单的方法:检查 UISCrollview 的平移手势识别器。有了它,你可以得到这样的速度:

CGPoint scrollVelocity = [[_scrollView panGestureRecognizer] velocityInView:self];

【讨论】:

  • 好用!唯一的缺点是scrollVelocity 将在用户抬起手指后立即变为 0.0f(因为这会结束平移手势)。所以这是在拖动滚动视图时测量速度的好方法,但如果轻弹则不起作用。
  • ..当然 panGestureRecognizer 仅在 iOS 5 及以后版本中公开。
  • 滚动速度是一个点,因为它记录了垂直和水平速度吗?
  • 正如@KyleFox 所说,是的,当然是的,使用scrollViewWillEndDragging:withVelocity:targetContentOffset: 来处理当前触摸事件结束后的速度或偏移条件
  • 这是触摸输入的速度,不是scrollView。
【解决方案4】:

对于简单的速度计算(所有其他答案都比较复杂):

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGFloat scrollSpeed = scrollView.contentOffset.y - previousScrollViewYOffset;
    previousTableViewYOffset = scrollView.contentOffset.y;
}

【讨论】:

  • 这也帮助了我,谢谢!其他人可能会考虑将 fabsf() 放在那里,只是为了获得绝对值。
  • 你需要考虑时间,否则速度会抖动。
  • 除了抖动问题之外,另一个问题是如果我更改 scrollView 的 contentInset 它将被注册为快速滚动。我无法区分这两个事件。
【解决方案5】:

这可能会有所帮助

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset

【讨论】:

  • 想提一下,这是速度输出的示例:(0.0,-5.35356)。按 y 轴滚动,5.35.. -> 每次scrollViewDidScroll 调用 15 个点 :) 所以,5 非常快。
【解决方案6】:

将@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
        
    }
}

【讨论】:

    【解决方案7】:

    这是在 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 时说过。所以我想知道,你如何改变滚动的速度?
    • 我的意思是用户滚动速度。如果循环捕获滚动速度,则此功能,所以我的意思是您可以更改该速度。你不能改变滚动速度:)
    • 这仅在视图被手指抛出时才相关。
    【解决方案8】:

    2017...

    使用现代 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
        }
    

    这是在手机上“略读工程”的基础。 (这是一个大而困难的话题。)

    请注意,这不是一个完整的略读解决方案;您还必须注意不寻常的情况,例如“它已停止”“屏幕刚刚关闭”等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-09
      • 1970-01-01
      • 2011-01-02
      • 2011-08-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多