Developing twitter splash screen for iOS application

Kostya Bunsberry
6 min readMar 7, 2022

--

Hello everybody ✋

This tutorial is mostly a different version and a translation of this article (original is in Russian)

So, the other day I noticed how awesome Twitter app launch animation looks like and I decided to replicate it for learning (as we always do sometimes 👀). I started looking for tutorials and it appears there wasn’t any solution, that I was happy with. Some of them may copy the animation of image, but it doesn’t “fall through” to the main screen as it is in the original app. Here is the original animation:

What we need to do?

At first sight, not much work to do for us, the most complicated part is writing the animation, everything else is just “routine work”. Classic situation: we show one screen then animate the transition to another — easy peasy.

In terms of animation we show a split screen with a hole, where we can see contents of the next page, like feed in twitter, so the logical solution is to make inital contoller the one we need to show after split screen.

So the problem with most splash screen solutions is they are called for just one concrete view controller but what if the user opens application by tapping on a notification, that leads to profile controller? The animation won’t be visible for user and that is a shame.

To avoid a lot of if-else statements on every controller that opens, we need to call it globaly on UIWindow, no matter which screen user should open on application lauch, we show the splash screen anyway. So we need to do 3 things:

  1. Prepare the splash screen
  2. Make it appear
  3. Make it disappear in a fashionable way

Preparing the spash screen

At first we need a static splash screen — the one that appears right when we open the app, you can do this by editing LauchScreen.storyboard

LaunchScreen.storyboard

It’s pretty simple, just one UIImageView with twitter logo and content mode set to aspectFit, also a blue backgroundColor for the contentView of the “controller”.

As you probably know, we can’t animate this screen, so we need to create another identical one, in this example I did it in Main.storyboard. Also I created the view that will be seen after the splash screen.

Left is splash screen we will animate, right is just two labels

Now let’s create the SplashViewController class:

So now you should go back to the main storyboard and define splash screen’s class to SplashViewController (set Storyboard ID to SplashViewController and check the box “Use Storyboard ID” as well for the future code), also you already should add something to the initial controller in main storyboard, so you can really see the mask magic.

Now we need a Presenter, in which we will describe present and dismiss splash screen logic. We need to create a protocol and a class.

In the beggining I said that we have to show it in a separate UIWindow, for that we need to:

  • Create a UIWindow
  • Create a SplashScreenController and make it rootViewController
  • Define windowLevel bigger than .normal (default value), so the window would show up over the main one

In SplashPresenter we add:

Maybe it seems weird to create instances of splash window and splash controller in separate methods but we’ll need it later.

We didn’t even start to write the animation and SplashPresenter already has a lot of code, let’s create one more class named SplashAnimator, which will only do animation — so there is less code in presenter (also we are delegating some duties).

We pass the foregroundSplashWindow and for convinience “extract” rootViewController from it which we store as foregroundSplashViewController

Add this to SplashPresenter:

And change it’s present() and dismiss() methods:

Now the boring part is over, we can start animating!

Making it appear

Here we can also make logo bigger or smaller but we are making the twitter splash screen, so all we need is to make UIWindow appear without anybody knowing the difference between launch screen and our controller.

The UIWindow is invisible by default, so to make it visible we can either call its makeKeyAndVisible method or set isHidden to false. Second solution is better for us as we don’t want foregroundSplashWindow to be our keyWindow.

Knowing that let’s add this to our SplashAnimator:

Now the only thing left for us to make it appear is to add SplashPresenter to AppDelegate and call its present() method. Also let’s make it dismiss in 1 second, so we don’t edit AppDelegate again later on.

The object gets removed after dismissing the splash screen.

Making it disappear

Sadly (or not), disappearing animation can’t be just 10 lines of code. We need to make a hole in form of image which will even get bigger! If you thought “you can do this with a mask”, you are absolutely right!

We are going to add our mask to the layer of main app window (because we don’t want to be tied to a concrete controller). Let’s do this and hide foregroundSplashWindow right away, because further actions will take place under it.

It’s important that you hide foregroundSplashWindow with alpha, not isHidden (otherwise the sceen will blink). Another interesting moment: considering that this mask will become larger during the animation, we need a logo of bigger resolution (at least 1024x1024, but svg and pdf versions are better). So I added this to SplashController:

You could notice that during animation logo doesn’t become transparent instantly, it should be animated as well. For this we add a UIView over all subviews in mainWindow, which will fade out.

So now we need to take care of blue background, because if we’ll run it now there won’t be one. Any ideas how to do this? I do. Let’s add another UIWindow underneath mainWindow and call it backgroundSplashWindow. Of course its rootViewController is going to be SplashViewController, but we’ll need to hide logoImageView. For this we’ll add a new variable in SplashViewController:

And in viewDidLoad() add this:

Let’s do add another thing in SplashPresenter: to method splashViewController() we need to add a argument logoIsHidden: Bool, which we’ll pass to SplashViewController:

Naturally, we need to pass false in this argument for foregroundSplashWindow, and true for backgroundSplashWindow:

Also we need to pass this object through init to SpashAnimator (just like we do for foregroundSplashWindow) and add these variables there as well:

So to see the same splash screen instead of black background, we need to show backgroundSplashWindow just before dismissing animation of foregroundSplashWindow:

Now the most interesting part — the animation itself! Considering that we need to animate CALayer, not UIView, we’ll use CoreAnimation. Here is our scaling animation:

Final scale is calculated depending on screen size (proportionally to its height). When screens height is 667 points (iPhone 6) twitter logo should scale up 36 times.

But at first it will scale down a bit (as we describe with second values in scales and keyTimes arrays). So at 0.4 * duration moment of time scale logo will be equal to 0.75.

We are almost finished! In animateDisappearance() we start all animations:

I used CATransaction to perform these actions, before animation is finished. In this case it’s more convenient that animationGroup, because not all of animations are done via CAAnimation.

And now we’re done! Here is the result:

Conclusion

And now we have a component, which does not depend on context of application launch (no matter if it’s launch by tapping notification, regular launch or something else). Animation will work correctly anyway!

You can download the project here.

--

--