iPhone UIScrollView Speed Check

后端 未结 8 1627
梦如初夏
梦如初夏 2020-11-30 19:31

I know how to get the contentOffset on movement for a UIScrollView, can someone explain to me how I can get an actual number that represents the current speed of a UIScrollV

相关标签:
8条回答
  • 2020-11-30 19:59

    Have these properties on your UIScrollViewDelegate

    CGPoint lastOffset;
    NSTimeInterval lastOffsetCapture;
    BOOL isScrollingFast;
    

    Then have this code for your 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;
        }
    }
    

    And from this i'm getting pixels per millisecond, which if is greater than 0.5, i've logged as fast, and anything below is logged as slow.

    I use this for loading some cells on a table view animated. It doesn't scroll so well if I load them when the user is scrolling fast.

    0 讨论(0)
  • 2020-11-30 20:00

    For a simple speed calculation (All the other answers are more complicated):

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView
    {
        CGFloat scrollSpeed = scrollView.contentOffset.y - previousScrollViewYOffset;
        previousTableViewYOffset = scrollView.contentOffset.y;
    }
    
    0 讨论(0)
  • 2020-11-30 20:03

    May be this would be helpful

    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
    
    0 讨论(0)
  • 2020-11-30 20:05

    There's an easier way: check the UISCrollview's pan gesture recognizer. With it, you can get the velocity like so:

    CGPoint scrollVelocity = [[_scrollView panGestureRecognizer] velocityInView:self];
    
    0 讨论(0)
  • 2020-11-30 20:07

    2017...

    It's very easy to do this with modern 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)")
    

    Of course you want the velocity in points per second, which is what that is.

    Humans drag at say 200 - 400 pps (on 2017 devices).

    1000 - 3000 is a fast throw.

    As it slows down to a stop, 20 - 30 is common.

    So very often you will see code like this ..

        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
        }
    

    This is the basis for "skimming engineering" on mobiles. (Which is a large and difficult topic.)

    Note that that is not a complete skimming solution; you also have to care for unusual cases like "it has stopped" "the screen just closed" etc etc.

    0 讨论(0)
  • 2020-11-30 20:12

    Converted @bandejapaisa answer to Swift 5:

    Properties used by UIScrollViewDelegate:

    var lastOffset: CGPoint = .zero
    var lastOffsetCapture: TimeInterval = .zero
    var isScrollingFast: Bool = false
    

    And the scrollViewDidScroll function:

    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
            
        }
    }
    
    0 讨论(0)
提交回复
热议问题