Why does UIScrollView scroll violently when I quickly swipe twice in the same direction?
Asked Answered
B

4

12

when scrolling horizontally in a UIScrollview, if I quickly swipe twice in the same direction the scroll view jumps violently. Is there anyway to prevent this from happening? To explain in detail, here's an event log from the scrollview where in most delegate methods I just print the x coordinate.

scrollViewWillBeginDragging:
    14:55:12.034 Will begin dragging!
    14:55:12.037 - Position -0.000000
scrollViewWillBeginDeceleration:
    14:55:12.129 Deceleration rate 0.998000
    14:55:12.152 + Position 314.000000
scrollViewWillBeginDragging:
    14:55:12.500 Will begin dragging!
    14:55:12.522 - Position 1211.000000
scrollViewWillBeginDeceleration:
    14:55:12.530 Deceleration rate 0.998000
    14:55:12.533 + Position 1389.000000
scrollViewDidScroll: (printing values < 0 && > 6000 (bounds.size.width)
    14:55:12.595 !!! Position 7819.000000
    14:55:12.628 !!! Position 9643.000000
    14:55:12.658 !!! Position 10213.000000
    14:55:12.688 !!! Position 10121.000000
    14:55:12.716 !!! Position 9930.000000
    ... contentoffset.x drops with around 400 each scrollviewdidscroll call ...
    14:55:13.049 !!! Position 6508.000000
scrollViewDidEndDecelerating:
    14:55:13.753 Will end deceleration
    14:55:13.761 * Position 6144.000000

The most notable thing in the log is right after scrollViewWillBeginDeceleration when the contentoffset.x jumps with ~6000 points in a matter of milliseconds.

Implementation

The uiscrollview and uiscrollviewdelegate are in the same class, a subclass of uiscrollview which also implements the uiscrollviewdelegate protocol, nothing special is done to contentoffset, and the only properties set on the scrollview are:

    self.showsHorizontalScrollIndicator = YES;
    self.scrollsToTop = NO;
    self.delegate = self;

The scrollview subviews are added once from a viewwillappear call in a uiviewcontroller which hosts the uiscrollview (and the contentSize is set appropriately). Scrolling, waiting a little while, and scrolling again works perfectly.

Beaudry answered 29/7, 2011 at 13:16 Comment(3)
It seems the underlying cause was a background color with [UIColor colorWithPattern:...] creating a slight lag while drawing, where none of the subviews in the scrollview were moved or drawn, but contentOffset.x was still increased. When the scrollview finally got around to moving, the contentOffset.x had increased drastically, even gone well beyond the bounds of the content, causing the view to jump to that offset in a horrible way. By using a lighter (or no background) I was able to get smoother scrolling.Beaudry
what if you put your background in another view behind your scroll view and set your scroll view's background color to transparent?Donkey
Are you using any custom acceleration equations that directly update the scrollview's offset values to perform scroll animation?Excellent
T
1

Please set the scroll view in your required direction and as well as co-ordinate for which you want the scroll and use the proper connection to XIB then it will work fine.

Tarttan answered 27/12, 2012 at 6:3 Comment(0)
A
0

May be you need to setup the bouncesZoom property?

scrollviewobject.bouncesZoom = NO;
Assegai answered 8/10, 2011 at 11:12 Comment(0)
P
0

you can try it like this

- (void)enableScrollView
{
    scrollView.userInteractionEnabled = YES;
}

- (void)delayScroll:(id)sender
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    //delay userInteraction 0.1 second, prevent second swipe
    [NSThread sleepForTimeInterval:0.1];
    [self performSelectorOnMainThread:@selector(enableScrollView) withObject:nil waitUntilDone:NO];
    [pool release];
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    scrollView.userInteractionEnabled = NO;
    [NSThread detachNewThreadSelector:@selector(delayScroll:) toTarget:self withObject:nil];
}
Pirzada answered 9/2, 2012 at 6:54 Comment(0)
S
0

If you want the UIScrollView to scroll a bit slower you could for example add a NSTimer when user scroll's and set the scrollers contentOffset a bit back with an animation like so:

Declare in .h File:

UIScrollView *myScrollView;
NSTimer *scrollCheckTimer;
BOOL delayScroll;

.m File:

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    if (delayScroll == YES) {
        [scrollCheckTimer invalidate];
        delayScroll = NO;
        [myScrollView setContentOffset:CGPointMake(myScrollView.contentOffset.x - 40, contentOffset.y) animated:YES];
    }
    delayScroll = YES;
    scrollCheckTimer = [NSTimer scheduledTimerWithTimeInterval:0.9 target:self selector:@selector(removeDelayBecouseOfTime) userInfo:nil repeats:NO];
}

- (void)removeDelayBecouseOfTime { delayScroll = NO; }
Swint answered 30/5, 2012 at 4:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.