4

I am trying to get the velocity of a scrolling UIScrollView after the user has lifted his/her finger so that I can trigger an event when the scrollview's velocity drops below a threshold velocity.

The Apple documentation states that the units for a scrollview's velocity are in points and I would guess that would be per second (pts/s), e.g., for UIScrollView Delegate method - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset.

I would therefore assume that the units for a scrollview's deceleration would be points per second per second (pts/s^2) but this does not seem to be the case.

Here are some example parameters pulled from a scrolling scroll view as soon as the pan gesture event ends (i.e., as soon as you lift your finger) pulled from methods - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffsetand - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView:

(Initial offset, Target offset, Initial Velocity, Final Velocity, Deceleration, Elapsed Time) =

  • (364.0, 2664.5, 4.619940, 0, 0.998, 3.068916)
  • (2595.5, 3288.5, 1.398724, 0, 0.998, 2.485449)
  • (3094.5, 1907.0, -2.389578, 0, 0.998, 2.752163)
  • (143.0, 1275.5, 2.279252, 0, 0.998, 2.718653)

where:

  • Initial offset = scrollView.contentOffset.y as soon as finger is lifted
  • Target offset = targetContentOffset->y as soon as finger is lifted or scrollView.contentOffset.y when scrollview is done decelerating
  • Initial velocity = velocity.y as soon as finger is lifted
  • Final velocity = 0 because letting scrollview scroll until it stops naturally
  • Deceleration = scrollView.decelerationRate as soon as finger is lifted
  • Elapsed time = time between when finger is lifted and when scrollview comes to rest
Ken M. Haggerty
  • 24,902
  • 5
  • 28
  • 37
  • I can't really answer the question, but I have two remarks: 1) The velocity can't possibly be in pts/s. If that was the case, it would take over 8 *minutes* in your first measurement to get from the initial offset to the target, even if there was no deceleration at all (4.6 points per second is extremely slow). 2) The `decelerationRate` property never changes in response to gestures, If you don't set it explicitly at some point, it'll always be the constant `UIScrollViewDecelerationRateNormal` (`0.998`), as in all your measurements. – omz Apr 22 '13 at 20:43

2 Answers2

4

The most important delegate method for your purposes is probably scrollViewDidScroll:, because you just keep getting sent that message over and over and over, including during the deceleration. Monitoring what's happening is going to be more use to you than trying to calculate in advance. There are no useful "units for a scroll view's deceleration" - that is to say, you don't have any information that could allow you to calculate in advance a velocity at every moment during the deceleration. However, scrollViewWillEndDragging:withVelocity:targetContentOffset: tells you the velocity now and the offset that the scroll view will have when the velocity is zero, and you can ask for the offset now, so you can decide on an offset between the current offset and the final offset, and monitor the remainder of the scrolling as it proceeds, in scrollViewDidScroll:, to learn when that offset is passed. And of course you can take a timestamp every time scrollViewDidScroll: is called, so with that and the instantaneous offset, along with the record from all the previous calls, presto, there's your instantaneous velocity.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 6
    Thanks! Also, it turns out that the velocity (as is obvious) is *not* points per second but rather points per iteration. What happens is that every X number of seconds the scrollview advances Y number of points, while X seconds later it advances Y*Z number of pixels where Z = `scrollview.decelerationRate`, Y = "velocity" (as via `scrollViewWillEndDragging:withVelocity:targetContentOffset:`), and X = 1/(iterations per second). This continues until the scrollview comes to rest. – Ken M. Haggerty Apr 22 '13 at 22:35
  • @KenHaggerty Extremely useful. Thanks for figuring that out! – matt Apr 23 '13 at 00:24
  • 1
    IRC! irc.freenode.net #iphonedev. You just have to put up with snark and people telling you you're stupid and worthless, but eventually you'll get an answer. – Ken M. Haggerty Apr 23 '13 at 19:47
  • @KenHaggerty This is interesting because the header file comment says that velocity is points/second. I can't see how points/second makes sense given the magnitude of the numbers I observe, so I'm inclined to believe your explanation and assume the comment is wrong. – Rob Jones Jul 28 '13 at 04:30
  • @KenHaggerty What do you mean by 'iterations per second'? Also, is your distinction between points and pixels deliberate? – Rob Jones Jul 28 '13 at 04:32
  • I realize this is an old discussion, but what is the average iteration rate? – Travis Griggs Dec 02 '14 at 22:46
0

Velocity units of UIScrollView is measured in pt/ms meanwhile velocity units of UIPanGestureRecognizer measured in pt/s

Andrey M.
  • 3,021
  • 29
  • 42