Infinite scroll using UIScrollView with paging

Seemingly easy technique, which benefits from good mental model to untangle the kinks

Infinite Scroll by Josh & Eliza, WWDC 2011

Normally, when you left swipe on a scroll view, you get the impression that your screen flows toward the left. However, iOS is just giving you that impression by moving the view port to the opposite direction. In the next example, only lime green part of the scroll view was visible before the left swipe showed the yellow part. In this example, entire scroll view didn’t change, but only the view port moved to the right to show the yellow part.

Swiping to the left causes the view port to move to the right

With this normal scrolling behavior, you will get stuck at the edge of Content View.

Normally, the scroll stops at the end of the content view

The key idea of the technique introduced by Josh & Eliza was to do the followings in UIScrollViewDelegate.scrollViewDidScroll(...)

  • Move the Content View to the direction of the swipe and keep viewport always in the center of the Content View
  • Add new contents in the newly open space of the Content View

With this technique, we never get stuck at the edge of the Content View, because the the view port is always at the center. As long as our program keeps feeding new contents into the open space properly, we will be able to scroll forever.

UIScrollViewDelegate.scrollViewDidScroll(...) is one of the best places to describe adjusting actions of the scroll, because it is called every time the view port moves, and also before the actual layout/rendering happens.

Scroll with paging

Problem

UIScrollView has a flag called isPagingEnabled. By just setting this flag to true, the scroll snaps beautifully at each page. Please look at the following example of “Animal peek-a-boo” sample app. You want every scroll to snap at each animal as you see in the gif. Otherwise, it is not peek-a-boo :)

I bet kids won’t be happy if the scroll just stopped at one point, so that’s the motivation to make this as an infinite scroll view.

If we naively implement Josh & Eliza’s technique in this app, it will break the paging functionality of the UIScrollView. Remember that the key idea of Josh & Eliza was to keep the view port at the center of the Content View. This makes iOS think that the scroll view is not moving across the page at all. As a result, the page snap will never happen correctly. So… Houston, we have a problem.

Solution

We don’t need to adjust the view port that often. Josh & Eliza is doing too much for simplicity of the code.

Josh & Eliza did the adjustment of the viewport every time when scrollViewDidScroll(...) was called. But actually, when you think about it, there are only two timings when we really need it.

  • When the view port moved to the right, and the next page content occupied the majority of the viewport. We need to bring back the view port to the left so that view port won’t get stuck at the right edge in the near future.
  • When the view port moved to the left, and the previous page content occupied the majority of the viewport. We need to bring the view port forward to the right so that view port won’t get stuck at the left edge in the near future.

You just need to adjust the viewport for the size of a page, and fill in the next content. Beautiful thing about this tweak is that it leaves the normal scrolling at the edge of each page, so the page snap works happily too.

Code

The corresponding code looks as follows :

Summary

When you need paging, the vanilla method will not work, but you can apply the same concept by limiting the timing of the adjustment. Some articles I read requires 5 pages, but in fact, you only need to prepare 3 pages by making adjustment in the middle of the page.

I think you can do similar thing with UIPageViewController as well, but it will require UIViewController to be the page member, and there are many cases where you don’t want to create UIViewController for each member. It is also big to note that UICollectionView and UITableView inherits from UIScrollView and the technique should be directly applicable when using those common UI elements.

The “Animal peek-a-boo” sample code is in the github. Please feel free to take a look if you are interested, and let me know if you have any feedback etc.

Coding in Swift, want to learn Flutter, a Dad, a Rock Climber, learning Parkour and Guitar

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store