0

I would like my UIScrollView to naturally glide to endings at certain incremental values, corresponding to every 50 points of width of a horizontally-scrolling UIScrollView To do this, I customed scrollViewWillEndDragging, like so (as recommended, but not described in detail in an answer here Scrolling a horizontal UIScrollView in stepped increments?):

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

    if(fmodf(targetContentOffset->x, 50.0)){
        int roundingNumber1 = 50;
        CGFloat newOffset = roundingNumber1 * floor(((scrollView.contentOffset.x)/roundingNumber1)+0.5);
        targetContentOffset->x = newOffset;
    }

}

However, I am not sure this is actually stopping the view at specific increments, and I also notice that the effect is asymmetric. Though my scrolling motions/velocity/etc are the same, scrolling right is much less fluid than scrolling left. Scrolling right stops faster and more abruptly. There's a video here. Why is this behavior asymmetric and how can I change it?

The reason I thin the scrolling is not stopping at increments of 50 is that I also have a UILabel underneath the scroll view that gets updated by other delegate functions to show the offset. The value it shows is rarely close to 50 when the scrolling is done. Is this because the scrolling is not incrementing to values of 50 or because I am not updating at the right times?

Thanks for any advice.

- (void) scrollViewDidScroll:(UIScrollView *)scrollView{

    if(abs(self.lastOffset - scrollView.contentOffset.x) > 49){
        CGFloat newNumber = scrollView.contentOffset.x;
        self.numberProperty.text = [NSString stringWithFormat:@"%.00f", scrollView.contentOffset.x];
        self.lastOffset = scrollView.contentOffset.x;
        [self.view setNeedsDisplay];
    }
}

- (void) scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView{
            self.numberProperty.text = [NSString stringWithFormat:@"%.00f", scrollView.contentOffset.x];
}
Community
  • 1
  • 1
sunny
  • 3,853
  • 5
  • 32
  • 62
  • In you delegate method - (void) scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset replace the 'contentOffset' by '*targetContentOffset' in the new target offset computation. – MiKL Jul 25 '15 at 17:44

1 Answers1

2

Rather than implementing these delegate methods, you can set pagingEnabled on your scroll view to true to get this behavior for free. When paging is enabled, the scroll view will automatically snap to the nearest "page" when you end dragging, where the page width is equal to the scroll view's width.

Based on your video, it looks like the items in your scroll view are smaller than the width of the scroll view itself. To use paging, you'll have to do the following:

  1. Make your scroll view have the same width as one of your items (50.0 units in your case).
  2. Set scrollView.clipsToBounds to false so that the scroll view draws subviews outside of its much smaller bounds.
  3. Set scrollView.pagingEnabled to true so that the scroll view scrolls with paging.

At this point, paging will work but you won't be able to drag the scroll view outside of its bounds. To make this work, you'll need to embed the scroll view in a larger view that forwards touch events to it.

  1. Create a "touch forwarding" class and add it to your view.

This class takes all touch events it receives and sends them to its targetView property instead. DJK is a random prefix I made up for the class name.

@interface DJKTouchForwardingView : UIView

/** The view to which touch events should be forwarded. */
@property (weak, nonatomic) UIView *targetView;

@end

@implementation DJKTouchForwardingView

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *child = nil;
    if ((child = [super hitTest:point withEvent:event]) == self) {
        return self.targetView;
    }
    return child;
}

@end
  1. Make the scroll view a subview of the touch forwarding view and assign it to the targetView property.

Your scroll view will now be scrollable within the bounds of the touch forwarding view and will snap to 50 unit pages.

Dklionsk
  • 203
  • 1
  • 5