To Infinity. Literally.
An "infinite loop," if you will...
There came a time, not so long ago now, where a user experience-related issue required me to think about things differently. While brainstorming the implementation for the onboarding of our latest and greatest app, I for some reason found myself thinking of every edge-case imaginable. Always fun.
One that caught my attention in particular, was the sheer length of the onboarding process. I thought that it would suck — on multiple levels — if the user had to swipe back a few pages, because they forgot what one of them said, and were subsequently forced to proceed once again to exit. The initial attempt at adequate mitigation of this issue resulted in a button that occupied the bottom of the screen — which contained the ever-so-tempting-copy of “Skip Tutorial.”
Frankly, I didn’t want the user to skip the tutorial that I had worked so tirelessly on. It was imperative that the user understand precisely how to use the app. So, keeping this in mind, I made the process slightly simpler by "trimming the fat" off the information, successfully condensing the number of pages down from 7 to 5.
But this solution didn’t solve the problem adequately enough for me to be truly happy with it. I felt like something was missing, and that that something would complete the experience so thoroughly that I’d never be able to top it. I picked up the phone I was using for QA at that time — an Android —to have a look for some platform-agnostic ideas, and the solution basically jumped right out at me within moments — an infinitely paging UIScrollView.
My first thought was one of regret. Why, why did I need to make my own life so very difficult? Any iOS developer will likely understand the struggles that Apple’s sometimes nonsensical limitations present to the individual. It’s borderline torture — first you’ve got to think differently, then you’ve got to get whatever it is working well enough to ship.
My second thought was to search Github, Google, and the omnipresent StackOverflow for this idea. My five minutes of searching revealed to me that many had tried to solve this problem and indeed done so, but that most of the solutions had unresolved issues or were written almost five years ago. Because of this, I decided to write my own in Swift. 🎉
Doing The Thing!
We’ll be making something like this:
The first thing you’re going to do, is create a new project in Xcode which uses the Single View Application template. Once this is done, create a new Cocoa Touch Class file, call it something like LoopyScrollThingy and ensure that its subclass is set to UIScrollView.
If any of the above felt like suddenly being asked to translate ancient Chinese battle hymns into Shakespearean English, please turn back now. It only gets worse from here.
Open up your new file if Xcode forgot how or you haven’t already, select everything, then paste this in:
- 1: Our variables.
- 2: We need this type of initialiser because we’ll be using Interface Builder to keep things simple a bit later on.
- 3: The setup() function adds the views you connected to the scroll view for you. It also sets its own contentSize.
- 4: The loadScrollViewWithPage() function, which takes a page parameter, adds the required page/s to the scroll view.
- 5: Method implemented from UIScrollViewDelegate. The scrollViewDidScroll method is responsible for updating the scroll view as you move.
- 6: Method implemented from UIScrollViewDelegate. The scrollViewDidEndDecelerating method gets called when the scroll view stops moving, and then updates the content offset if you’re at the end of the pageable content. This is the key.
Did I mention I’m really glad Swift 3 is removing unnecessary repetition of things like color and scrollView? 'Cause I am!
Making The Thing Work! Kinda!
Go ahead and open up your ViewController.swift file, or whichever UIViewController you want this contained in. This will likely be a menu or your very own onboarding process.
Declare yourself a weak IBOutlet, named whatever you like, ensuring that its of type LoopyScrollThingy?, then save.
Now, open up your storyboard and find the associated UIViewController container. Drag a UIScrollView object onto it, then give it AutoLayout constraints as follows:
Wire up the outlet you created before to this scroll view object, then save. Make sure that the object has its class set to LoopyScrollThingy too.
Back in your View Controller, and find the viewDidLoad() method. Highlight the entire method, and paste the following in:
- 1: We’re not using Interface Builder yet, but we will soon! 🙏 We’re creating three UIView objects, each with different colours, so we can tell them apart during scrolling.
- 2: We tell the scroll view how many pages we want, then give it the array of views.
- 3: Then we call setup() which sets up the different thing! 🎉
If you did the different thing properly, running the app in the Simulator will show you how well you did! You’ll see your first page displayed, and a quick swipe to the left gives you the 2nd one, etcetera.
Note: This can still break if you go too quickly at this stage. It’s designed to be paged at an "ordinary" pace.
Putting A UIPageControl On The Thing!
You’ll notice that there’re no page dots to speak of. I'm of an unrelenting, slightly manic belief, that this control is absolutely necessary for the user to know they can scroll the content. So we’ll add that now, in a few simple steps.
- Add a private UIPageControl variable to the LoopyScrollThingy class.
- Then replace the setup() method with this:
- And the scrollViewDidScroll() method with this:
Run the app and see that, YAAAAAS! It shows the page dots! 🎉
Building An Interface For The Thing!
If you don’t already feel like you can do everything ever, open up your View Controller again, and delete the three view objects and the line which feeds them to the scroll view. Your new viewDidLoad() should look similar to this:
Then open up the LoopyScrollThingy class, and change viewObjects into an IBOutlet, and add some extra UIView objects to your UIViewController’s container in the storyboard, like so:
You can put anything in them, really. Images, if you want, or cuss words. Whatever floats your boat. However as mentioned above, this effect works better with 3+ screens however we’ll rectify that in Part 2 of this tutorial series.
Now wire up the scroll view’s viewObjects property to each one of the views. Pay careful attention to the order, because this is the order in which they will appear on screen.
Run the app again. This time, the views you connected in Interface Builder are now the panels of your scroll view! You’ll see it doesn’t work perfectly, but that’s what we’ll fix in our next attempt at thinking differently.
At jtribe, we proudly craft software solutions for iOS, Android and Web and are passionate about our work. We’ve been working with the iOS and Android platforms since day one, and are one of the most experienced mobile development teams in Australia. We measure success on the impact we have, and with over six-million end users we know our work is meaningful, and this continues to be our driving force.