Unable to setContentOffset in scrollViewDidEndDrag

2019-02-25 04:26发布

问题:

I am attempting to modify the contentOffset of my scroll within the following delegate method:

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate

I have tried both of the following:

[UIView animateWithDuration:.2 animations:^ {
   [scrollView setContentOffset:CGPointZero animated:NO];
}];

and

[UIView animateWithDuration:.2 animations:^ {
   CGRect svBounds = self.bounds;
   svBounds.origin.y = 0;
   self.bounds = svBounds; 
}];

The problem is that although this changes the offset right away (proven by logs after the animation is complete), it doesn't change the visible scroll location. This is further proven by subsequent delegate methods of my scroll view which indicate that the bounds have indeed not changed at all. Meaning that the y location is not 0.

Is it forbidden to change the content offset in this particular delegate method? If so, when is it possible for me to change the offset? I'm trying to perform an animation of returning the visible scroll area to the top once the user finishes dragging (after a certain amount).

Thanks!

回答1:

what i did eventually is dispatching again to the main queue. meaning:

-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
NSLog(@"END DRAG");
CGFloat yVelocity = [scrollView.panGestureRecognizer velocityInView:scrollView].y;
if (yVelocity < 0) {
    NSLog(@"Up");
} else {
    NSLog(@"Down");
}

if (yVelocity < 0 && scrollView.contentOffset.y < -100 && scrollView.contentOffset.y > -200) //UP - Hide
{
    NSLog(@"hiding");
    dispatch_async(dispatch_get_main_queue(), ^{
        [scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
    });
}
else if (yVelocity > 0 && scrollView.contentOffset.y < -100) //DOWN - Show
{
    NSLog(@"showing");
    dispatch_async(dispatch_get_main_queue(), ^{
        [scrollView setContentOffset:CGPointMake(0, -300) animated:YES];
    });
}

}

and it actually works :-)



回答2:

You should "nil" your scrollView delegate before animation, set content offset in scrollViewDidEndDragging:willDecelerate: will cause repeat delegation.

self.scrollView.delegate = nil;
[self.scrollView setContentOffset:CGPointMake(x, y) animated:YES];
self.scrollView.delegate = self;


回答3:

Depending on the effect you are trying to achieve, you may have more luck with this delegate method:

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

You can choose what target content offset you want to use for the scroll view to decelerate to once the user stops dragging.