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.