27

Since this question was originally asked, UIScrollView deceleration rate customization has been added via the decelerationRate property introduced in OS 3.0.


I have a UIScrollView whose deceleration rate I'd like to change. To be clear, I'm talking about when you swipe your finger on a scroll view and the view continues to scroll (but gradually slows) after you lift your finger. I'd like to increase the deceleration rate so that it stops sooner that it does by default.

I've seen some apps where the UIScrollViews seem to decelerate more quickly. There seems to be no API for this in UIScrollView, but I'm wondering if there's an alternative way to do it.

Mike McMaster
  • 7,573
  • 8
  • 37
  • 42
  • That link is now: http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIScrollView_Class/Reference/UIScrollView.html#//apple_ref/doc/uid/TP40006922-CH3-DontLinkElementID_2 – Sixten Otto Feb 10 '11 at 02:09
  • It's now VERY EASY to do this beyond the two given values. – Fattie Mar 03 '23 at 18:23

5 Answers5

55

You can use UIScrollView's decelerationRate property to control it. Even though its float, its not accepting any value other than UIScrollViewDecelerationRateNormal or UIScrollViewDecelerationRateFast . Look at the following code

NSLog(@"1. decelerationRate %f", scrollview.decelerationRate);

scrollview.decelerationRate = UIScrollViewDecelerationRateNormal;
NSLog(@"2. decelerationRate %f", scrollview.decelerationRate);

scrollview.decelerationRate = UIScrollViewDecelerationRateFast;
NSLog(@"3. decelerationRate %f", scrollview.decelerationRate);

scrollview.decelerationRate = 0.7;
NSLog(@"4. decelerationRate %f", scrollview.decelerationRate);

scrollview.decelerationRate = 0.995;
NSLog(@"5. decelerationRate %f", scrollview.decelerationRate);

Above code gives the following outputs, its very clear we cant not use custom deceleration rate.

2012-01-03 11:59:41.164 testviewv2[10023:707] 1. decelerationRate 0.998000
2012-01-03 11:59:41.172 testviewv2[10023:707] 2. decelerationRate 0.998000
2012-01-03 11:59:41.173 testviewv2[10023:707] 3. decelerationRate 0.990000
2012-01-03 11:59:41.175 testviewv2[10023:707] 4. decelerationRate 0.990000
2012-01-03 11:59:41.176 testviewv2[10023:707] 5. decelerationRate 0.998000

Ten years later! Apple finally stated this in the doco:

https://developer.apple.com/documentation/uikit/uiscrollview/decelerationrate

Fattie
  • 27,874
  • 70
  • 431
  • 719
Anto Binish Kaspar
  • 1,322
  • 1
  • 14
  • 20
  • I have found the same behaviour – Robert Wagstaff Dec 12 '12 at 06:56
  • 1
    confirmed. this must be documentation issue – Marcin Dec 12 '12 at 10:14
  • 1
    Unfortunately it's true. I would like to have at least a value between these two, like 0.994, but it's not working. – Grzegorz D. Jan 31 '13 at 13:55
  • Great catch. I was inserting lots of values that were inbetween the two and noticing it didn't feel different. Then I tried 1.1 and 0.5 with the same results. Your code snippet performs the same – VaporwareWolf Sep 05 '13 at 19:19
  • @grzegorzdvipek I happened to see a single line in Apple's demo like this. `float decel = UIScrollViewDecelerationRateNormal - (UIScrollViewDecelerationRateNormal - UIScrollViewDecelerationRateFast)/2.0;` I logged and found its value is 0.994000 as you wanted. Hope it helps. – Calios Nov 23 '15 at 03:27
38

Yes, I have successfully changed the deceleration rate by doing the following:

scrollView.decelerationRate = UIScrollViewDecelerationRateFast;
shim
  • 9,289
  • 12
  • 69
  • 108
yeahdixon
  • 6,647
  • 1
  • 41
  • 43
  • decelerationRate is actually a float, so you can have more detailed control by entering any float value. – CharlieMezak Jan 14 '11 at 21:07
  • 5
    @CharlieMezak It's a float but only works with the UIScrollViewDecelerationRateFast and UIScrollViewDecelerationRateNormal values. –  Dec 16 '14 at 15:47
  • you can ONLY USE the two values supplied. it's not really a float. – Fattie Mar 03 '23 at 18:01
17

I found that by using KVC to modify the instance variable _decelerationFactor allowed me to change the rate to something other than UIScrollViewDecelerationRateNormal or UIScrollViewDecelerationRateFast. I subclassed UIScrollView and wrapped the whole lot in a try block

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        @try {
            CGFloat decelerationRate = UIScrollViewDecelerationRateFast +(UIScrollViewDecelerationRateNormal - UIScrollViewDecelerationRateFast) * .52;
            [self setValue:[NSValue valueWithCGSize:CGSizeMake(decelerationRate,decelerationRate)] forKey:@"_decelerationFactor"];

        }
        @catch (NSException *exception) {
            // if they modify the way it works under us.
        }


    }
    return self;
}
mackross
  • 2,234
  • 17
  • 19
  • 5
    Sounds like a quick way to get your app rejected. – Glenn Maynard Feb 11 '13 at 00:08
  • 6
    I've not had problems with it but it is in a bit of a grey area. In that you can see the variable directly in the header file and don't need to class dump. I feel it falls into the realm of go for it if it improves user experience but don't let it crash your app. – mackross Feb 11 '13 at 00:37
  • 1
    @mackross Soooo this was posted in 5 years ago, has anyone gotten this solution into the app store? – AntonTheDev Nov 01 '18 at 21:51
0

It's now very easy to do this:

extension UIScrollView {
    
    ///The usual values are .998 (fast) and .990 (normal).
    ///0.92 for example is a crisp spring effect.
    var customDecelerationFactor: CGFloat {
        set {
            setValue(CGSize(width: newValue, height: newValue),
                     forKey: "_decelerationFactor")
        }
        get { return 0 }
    }
}

For example ...

enter image description here

It's completely unknown (as of 2023) if Apple have "_decelerationFactor" on the list of keywords in code they question when you submit to the app store.

halfer
  • 19,824
  • 17
  • 99
  • 186
Fattie
  • 27,874
  • 70
  • 431
  • 719
-1

There is a pretty straightforward approach. Override the setter method.

@interface UIArbitraryDeceleratingScrollView : UIScrollView

@property(nonatomic,assign) CGFloat decelerationRate;

@end

@implementation UIArbitraryDeceleratingScrollView

@synthesize decelerationRate = _decelerationRate;

- (void)setDecelerationRate:(CGFloat)dr
{
    [super setDecelerationRate:dr];
    _decelerationRate = dr;
}

@end

Now assign what you want to, like this for example:

_scroller.decelerationRate = (UIScrollViewDecelerationRateNormal+UIScrollViewDecelerationRateFast)/2.1;
Fattie
  • 27,874
  • 70
  • 431
  • 719
  • This doesn't work. The scroll view is probably directly accessing the private member variable and not the property. – Cal Nov 27 '18 at 19:47