How we built our Onboarding Framework

If you have ever downloaded an app and it took you forever to figure out the way it works you probably know that onboardings do make a difference. All cool apps have some kind of this helpful thing. And it stands for a reason.

An onboarding program for mobile app is a simple visual way to do exactly what they sound like – “get users on board”. Basically it’s a short graphic lesson on the basic functions and features of your app.

Good onboardings help users start using the app right away. It’s a really cool thing that makes your app get some brownies from happy users and probably helps you increase the retention rate of your application.

Now that we described all the upsides of onboarding tutorials let’s introduce the open source onboarding constructor for mobile apps we created. Let’s get it started!

Open source onboarding constructor for mobile apps

What motivated us to create LUNTutorialViewController?

Creating an onboarding for your app is a great thing to do. However, in order getting a decent onboarding takes lots of time and effort. We didn’t wanna spent lots of time on making cool onboardings for every app that would need it.

As we couldn’t find any frameworks for mobile app onboarding that would be customizable and cool enough, we decided to come up with our own onboarding tool with extended functionality.

And that’s exactly why our team decided to come up with a customizable library that would help people build amazing onboardings in the blink of an eye with a little effort.

Besides, you can customize our LUNTutorialViewControl as easy as pie, which comes in really handy if your app is at the stage of alpha or beta testing. Thanks to the simple customization model you can try out different kinds of onboardings to see which works best.

How did we create it?

Now that we’ve understood that onboardings are simply awesome, and in some cases they’re basically a must-have, our team decided to create an open source library named LUNTutorialViewController.

In order to make LUNTutorialViewController as customizable as possible we first had to get down to the nuts and bolts of onboardings. Our team came to a conclusion that every onboarding basically had the N-layer structure.

Open source onboarding library for iOS

The N-layer structure of onboardings

  • 0 – layer: Static Background. This might be either regular or gradient fill or sometimes an image.
  • 1 – layer: Dynamic Background. This layer represents the background that’s changed on switching between screens.
  • 2 – layer: Wireframe. It’s exactly what it sounds like. This might be a phone screen or an image of any other container (wireframe).
  • 3 – layer: Inner Wireframe. The content inside the phone screen or whatever container you got.
  • 4 – layer: Static Content. This is the type of content that stays on the screen at all times throughout the whole onboarding.
  • 5 – layer: Labels. These are the thingies to hold the text content. Labels content is usually different for each of the screens.
  • 6 – layer: Icons.

Some of these layers might be left out for different kinds of onboardings.

Step #1

In order to help you creating onboardings easily first thing we did was created a child of UIViewController named LUNTutorialViewController.

The point of its creation was an attempt to simplify the process of working with onboardings through code. All you need as a library user is define the kind of content you want and set animations (or simply use ones from our implementation examples).

For content setting you need to implement LUNTutorialDataSource protocol, which is basically a merge of LUNTutorial-DataSource’s, all of which represent one of the layers.

Once all the content is set you need to take care of animations. This is the job for an entity, which implements LUNTutorialAnimator protocol. LUNTutorialAnimator  is basically a merge of LUNTutorialAnimator’s for all the layers.

What happens next in LUNTutorialViewController with the content?

LUNTutorialViewController builds up the layout of your onboarding based on the restrictions you’ve set up for your Static Content and Text Part.

Here’s the way it works:

  1. staticBackground takes up the whole screen: all its width and height.
  2. dynamicBackground is enclosed in the LUNTapPassingScrollView backgroundsScrollView with disabled scrolling and enabled paging that takes up the entire screen.
  3. wireframes are positioned in the same backgroundsScrollView above the dynamicBackground in the hierarchy. They are horizontally and vertically aligned to the center with the current onboarding page.
  4. innerWireframes are located inside of wireframes and are vertically and horizontally aligned to the center with the wireframes.
  5. staticContentView is positioned above the backgroundScrollView in the hierarchy. Setting the height of the UIView  requires setting the staticContentHeight property of the LUNTutorialViewController.If you want the height of the UIView to be proportional to the screen size you can inherit from LUNTutorialViewController and then override getter of this property. Static content is stretched horizontally and anchored to the bottom of the screen.You can always adjust the static content position by returning an UIView with transparent subviews, that adjust the position of static content on the screen, into the LUNTutorialStaticContentViewDataSource.

LUNTutorialViewController has got a property named roundnessHeight. If it’s value is more than zero a mask, which basically is a circle segment, is gonna be laid on top part of the staticContentView. We used some basic math for the mask creation:

  1. The layer above the static content in the layers hierarchy is named LUNTapPassingScrollView labelsScrollView and it holds your text content.
  2. Our next layer is LUNTapPassingScrollView iconsScrollView, which lies on top of the text content and contains all the icons. Those icons are linked to the top of the staticContentViev.The icons also have a particular move path based on the roundnessHeight value set for staticContentView in a way that the move path of the icon matches the top edge of staticContentView.

On top of all this beautiful layout goes a LUNTapPassingScrollView mainScrollView – the only scrollView with scrolling enabled.

mainScrollView’s main task is pretty straightforward – scrolling the LUNTutorialViewController.

We need the scrollView so the scrolling would go synchronously (due to the discontinuity of the scrollViewDidScroll call one of the scrollviews might scroll faster than the other ones) and on top of any content passed by the user.

All listed above should work regardless the place a user starts scrolling (it can be on top of either static content or background or even wireframes).

LUNTapPassingScrollView works as follows: it simply lets taps go through itself if a UIControl is located below the tap.

Step #2

The next thing we do is go to the scrollViewDidScroll, which is called for the mainScrollView. Now we programmatically scroll all our scrollviews by the same offset value.

Frameworks for mobile app onboarding

After that all animator methods are called, having previously calculated which are the indexes we switch between, and how much of the screen has already been scrolled. Here’s the way it goes:

Define the page

Animate everything

For a better control over LUNTutorialViewController we created the LUNTutorialDelegate. Its methods are called on the LUNTutorialViewController’s state changing.

In order to get even more control over the LUNTutorialViewController you can use its subclass. This way you’re gonna get access to all the protected fields of LUNTutorialViewController.

How can you use LUNTutorialviewcontroller?

Let’s take a closer look at how the LUNTutorialViewController works by checking out an example called LUNAnimalsViewController.

Onboarding Animation with Rotation

First let’s create a child of the LUNTutorialViewController.

Then download all the assets used for this onboarding libarry for iOS creation.

Now let’s do the basic setup for the onboarding.

Next thing we do is set the content for our LUNTutotialDataSource.

Let’s start from the bottom layers. The background:

You’ll understand the importance of the contentMode value once we get to the animators.


Static content

(workaroundView is a UIView that’s gonna cast a shadow for the button because the shadow has an unusual way of cast)

Text content


Now our onboarding content is set. Next thing we do is set animations. It’s time to use our LUNTutorialAnimator.

The background

In order to get a neat background change effect we used big images that are switched with the help of crossfade animation as soon as they moved through a part of the screen.


A wireframe is rotated by a particular angle, so it’s moving along the part of the circle, represented by the top part of staticContentView, gradually fading out at the same time.

Text content

The text content is gradually fading when scrolling.

You can also add code to the reloadData method. In case of our LUNAnimalsViewController adding some code will generate an UIView that’s gonna cast a shadow for the static content view. This is caused by the fact that the view itself is cut off by a mask, which doesn’t let it cast its own shadow.

Now we got our beautiful ready-to-go onboarding. Now you see how easy and fast you can get yourself a ready-to-go easily customizable onboarding with a little time and effort!
All Onboarding animations


In this article we introduced our open source onboarding constructor LUNTutorialViewController for creating onboardings.

We hope it’s gonna be useful for a lot of people as it comes in really handy for developers of our team every time we need to create an onboarding for an app. If you ever need an onboarding framework for iOS you know where to find it!

Try on GitHub

If you have any questions regarding your future project, feel free to contact us. We kick asses when it comes to developing apps with smart custom design!