• invisible

UIScrollView Paging Hack

April 5th, 2009 by james

The paging property in UIScrollViews is pretty handy: for those unfamiliar, it’s the great snapping feature when leafing through images in your photo collection, for example. One unfortunate limitation is that the UIScrollView, as provided, only lets you snap on multiples of the frame size. We wanted to lay out smaller previews of images so you could see the previous and next images as well, something like this:
scroll1.png
It’s easy enough to lay out the images, but if you turn paging on then you end up snapping on every other item. The solution we use is to move our content within the scrollview so that it lines up properly when snapped, like so:
scroll2.png
This method is very simple to handle in the code: just put all the subviews into a container, set yourself as the scrollview delegate, and use the scrollViewDidScroll: callback method to set the CGAffineTransformTranslation of your container view to half the current content offset of the scrollview.

- (void) scrollViewDidScroll:(UIScrollView *)scrollView {
  CGFloat offset = scrollView.contentOffset.x/2;
  CGAffineTransform transform = CGAffineTransformMakeTranslation(offset, 0);
  [contentView setTransform:transform];
}


The view no longer scrolls one-to-one with your finger, but flicking works quite well.

5 Responses to “UIScrollView Paging Hack”

  1. jochen says:

    can you please explain, how “contentView” in your example is created/used? It would be perfect, if you could provide a complete controller-code for this example…!

    best regards & thanks

  2. james says:

    jochen: When using a scrollview, you generally need to add some subviews that contain the actual content to be scrolled. Instead of putting those subviews in the scrollview directly, you should add them to what I’m calling a container view, and then add the container view to the scrollview. If you’re still confused, I’d recommend checking out Apple’s documentation on using scrollviews and make sure you’re comfortable with their normal use before you try this technique.

  3. RickiG says:

    Hi
    I just found this post and had to do something similar. My issue was that I would like to divide an entire page into X smaller pages but still have the snap effect. This works really well:

    - (void)scrollViewDidEndDecelerating:(UIScrollView *)_scrollView {

    [self snapToPosition:_scrollView];
    }
    - (void)scrollViewDidEndDragging:(UIScrollView *)_scrollView willDecelerate:(BOOL)decelerate {

    [self snapToPosition:_scrollView];
    }

    - (void) snapToPosition:(UIScrollView *)_scrollView {

    CGFloat itemWidth = 80.0f;
    CGFloat position = [_scrollView contentOffset].x;
    CGFloat newPosition = 0.0f;
    CGFloat offSet = position / itemWidth;
    NSUInteger target = (NSUInteger)(offSet + 0.5f);

    newPosition = target * itemWidth;

    [_scrollView setContentOffset:CGPointMake(newPosition, 0.0f) animated:YES];
    }

    itemWidth is the size of the smaller subviews I build the content of the scrollView from.

  4. ludo says:

    Hi,

    Maybe someone can help me here. I have a scrollView with some pictures inside (10 pictures)
    and the screen can display 3 pictures.
    I want to be able to divide my scrollView in 3 parts, so when I scroll it will scroll part by part.

    How can I do that? I can’t make any of your code really work.

    Thank you

  5. ludo says:

    Don’t need to approve my older post, its working now ^^

    RickiG I use your method and divide my scrollView into 3 parts, everything is working fine.
    Now what I want is everytime an image appear in the middle of the scrollView and stop, I will display some information related to that Image into my view.

    But I don’t know how to do that. How can I know which image is in the middle of the scrollView?

    Thanks

Leave a Reply