Adjusting UIScrollView target offset can lead to strange linear-deceleration behavior

Originator:jtbandes
Number:rdar://18746849 Date Originated:10/22/2014
Status:Open Resolved:
Product:iOS SDK Product Version:8.1 (12B411)
Classification:UI/Usability Reproducible:Always
 
Summary:
When a UIScrollView's delegate adjusts its deceleration-target contentOffset, the scroll view can get into a strange state where it decelerates most of the way, then slides linearly.

One way this can happen is with very small scroll gestures (velocity < ~0.27).

We have also seen cases of this linear movement behavior with very fast scroll gestures, but the reproduction steps are currently unclear.

Steps to Reproduce:

Add the following code to an empty view controller; try scrolling with a very small velocity.

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(375/2.0-200/2, 180, 200, 300)];
    _scrollView.delegate = self;
    _scrollView.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1];
    _scrollView.alwaysBounceVertical = YES;
    _scrollView.clipsToBounds = NO;
    
    UIView *top = [[UIView alloc] initWithFrame:CGRectMake(5, 5, 190, 250)];
    top.backgroundColor = [UIColor colorWithWhite:0.7 alpha:0.8];
    UILabel *label = [UILabel new];
    label.text = @"Hello";
    [label sizeToFit];
    label.center = [top.layer convertPoint:top.layer.position fromLayer:top.layer.superlayer];
    [top addSubview:label];
    [_scrollView addSubview:top];
    
    UIView *boundary = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 1000)];
    boundary.layer.borderColor = [UIColor blackColor].CGColor;
    boundary.layer.borderWidth = 1;
    [_scrollView addSubview:boundary];
    
    _scrollView.contentSize = boundary.bounds.size;
    
    [self.view addSubview:_scrollView];
    
}


- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
                     withVelocity:(CGPoint)velocity
              targetContentOffset:(inout CGPoint *)targetContentOffset
{
    if (scrollView == _scrollView) {
        CGFloat maxY = (_scrollView.contentSize.height - _scrollView.bounds.size.height);
        targetContentOffset->y = MAX(0, MIN(1, round(targetContentOffset->y / maxY))) * maxY;
        NSLog(@"Target %g,  velocity %g", targetContentOffset->y, velocity.y);
    }
}


Expected Results:
Scroll-deceleration should always be exponential decay, never linear.

Actual Results:
Scroll deceleration is linear in certain cases.

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!