Infinite scroll using UIScrollView with pagingYuichi FujikiBlockedUnblockFollowFollowingFeb 4Seemingly easy technique, which benefits from good mental model to untangle the kinksInfinite Scroll by Josh & Eliza, WWDC 2011The technique of infinite scroll for iOS is known for years, although it has been considered difficult at times even today.
First time I heard about it was in WWDC talk by Josh & Eliza in 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 rightWith this normal scrolling behavior, you will get stuck at the edge of Content View.
Normally, the scroll stops at the end of the content viewThe key idea of the technique introduced by Josh & Eliza was to do the followings in UIScrollViewDelegate.
)Move the Content View to the direction of the swipe and keep viewport always in the center of the Content ViewAdd new contents in the newly open space of the Content ViewWith 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.
) 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 pagingProblemThe technique above is very easy to implement and it is very effective.
Except when you need paging.
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.
SolutionAs with everything in this world, there is a solution.
And this is a fairly easy one.
The key idea of the solution is thatWe 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.
CodeI am showing the sample code from the “Animal peek-a-boo” sample I demonstrated above.
In the sample, we have oneUIImageView and one UIImage for each page of the scroll view.
As illustrated above many times, we only need three pages for the infinite scroll view, so we prepare an array of threeUIImageViews and reuse them (called imageViews).
Whenever we adjust the position of the pages, we adjust the frame of those UIImageView s, and set new images to the UIImageViews.
The corresponding code looks as follows :SummaryWhen you want to implement an infinite scrollview using UIScrollView, you can do that by adjusting contentOffset and frames of its content views.
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.