UIScrollView paging size

Guides | Tutorial By 3 years ago

Now updated with example project, see end of post for link

I recently tackled a difficult problem at work.

In an app I’m currently working on we have a horizontal collection view with paging. The cells are spaced out and smaller than the collection view so the user can see a little bit of the left and right cell while the main cell is centered.

The problem I faced was with the paging. A UIScrollView’s page width is the same as its view’s bounds width. This means that the collection view would be paging too far and the cells would become misaligned.

Here’s a visual example. The top yellow cells show what happens with no fixes. You can see that when paged, the cells move the entire width (400 points) of the view. The bottom green cells show what effect is desired, where the cells only move the width of a cell plus the right gap (300 points).


The first solution I played with was having a different bounds compared to the frame of the collection view, with clipping to bounds turned off. This didn’t work because even though the cells would be visible when outside the bounds, the collection thinks they will be hidden and removes them from its view hierarchy.

I also tried playing with implementing paging myself, however it’s difficult to get feeling exactly the same as Apple’s built in paging, so I dropped this as an option.

In the end I found a pretty simple solution, albeit difficult to discover.

Instead of using the scroll view by itself I put a blank UIScrollView in front of it with the same content size with paging enabled. This blank scroll view had my target width of 300 points, aligned to cover the cell in the collection view behind. I grab the panGestureRecognizer instance from the overlay scroll view and disable it. I then add it as a gesture recognizer to the main scroll view, so its touch events are still processed by the overlay scroll view. I then forward all scroll content offset events to the collection view via the -scrollViewDidScroll: delegate method. This gave me the correct paging size I wanted.

Download example project here

  • Bilawal Liaqat

    Can you please post example project here.

    • Tom

      Hi there
      I’ve just added an example.
      I also improved my implementation to take use of gesture recognizers, some content in the post has also been updated.

      • Varun Goel

        hey Tom thanks a lot for putting up the example project.

        will this strategy work for any cell width ?

        in your example project the content size’s are different for the three scroll views.

        self.brokenScrollView.contentSize = CGSizeMake(3860, 0);

        self.scrollView.contentSize = CGSizeMake(3860, 0);

        self.invisibleScrollView.contentSize = CGSizeMake(3780, 0);

        why is that?


        • Tom

          Yes this should work, the content size is different because it is derived from the main scroll view’s content size minus the X origin of the invisible scroll view

  • Thomas

    I’m trying to implement this programmatically, but for some reason, it allows the contentOffset to be increased by any multiple of my invisibleScrollView width. For example, my invisibleScrollView width is 200 (which is what I want my paging size to be), but it allows the content offset to increase by 200, 400, 600, etc if a user swipes hard enough, when I only want it to be increased by 200. Any ideas?

  • Anton Bukov

    Great idea, changed it to more simple: http://stackoverflow.com/a/30365070/440168