Roni Leyes
The Aesthetic Programmer
8 min readMar 19, 2018

--

Facebook loading labels animation — Simple approach for Skeleton View in Swift 4

Final result:

Introduction

When you launch Facebook(Not from background), it fetches your feed.
While doing that, the labels and pictures have some gray colored placeholders on them with some moving gradient animation.

These views kind of tells the user what is going to be there and is showing the “skeleton” of the content that will appear in those frames. That’s where this loading type get it’s name from.

This type of loading is called: Skeleton Screen

Skeleton screens are way more user friendly than not showing anything, or a full screen loader, for example.
Users nowadays are also used to it.

Analyze

Before we begin, we need to understand the animation.

The gif generator kinda lowered the resolution and the frame rate, but you get the idea.

This animation is pretty simple.
It’s just a moving gradient, repeatedly moving from left to right, with a little delay between the loops.

You can’t really see it in the gif I uploaded so feel free to open Facebook and see for yourself.

If you can slow your internet somehow, even better. That way you can see a couple of loops of the animation before it shows you the actual content of the post.

Prepare the grounds

Create a new project, a single view application and go to Main.storyboard.

Add a view to the main view controller and set it’s background color to blue.

Add the following constraints to it:

  • Center vertically in superview
  • Align leading with superview
  • Align trailing with superview
  • Height = 40
You should end with something like this

We’ll test the animation on this view. So connect it to an IBOutlet and name it ‘SkeletonView’.

CAGradientLayer

In order to animate the gradient, let’s first create a gradient layer.

CAGradientLayer is what we’ll use.

Shortly, CAGradientLayer takes:

  • Start point — CGPoint
  • End point — CGPoint
  • Colors — [CGColorRef]
  • Locations — [NSNumber]

Start point and end point

Think of start point and end point as a stroke of a paint brush on the wall. The start point is where you start the stroke and the end point is where you lift the paint brush off the wall.

Those points use the unit coordinate system (More information on this can be found here). Those points are the layer’s bounds, translated relatively
from 0.0 to 1.0. Meaning that point (x:0.0,y:0.0) is the top left corner of the layer and point (x:1.0,y:1.0) is the bottom right corner of the layer.

Colors

From the docs :

An array of CGColorRef objects defining the color of each gradient stop.

Locations

From the docs:

An optional array of NSNumber objects defining the location of each gradient stop. Animatable.

and:

The values must be monotonically increasing

Basically, this means that if we decide to set a locations array, we need to add a value for each color element we set in the colors array, in an increasing order.

For example, if we want that the gradient to start from black and end in white, we’ll need to set out arrays like that:

Colors = [black,white]

Locations = [0.0,1.0]

0.0 black gradient stop and 1.0 is white gradient stop.

Adding gradient

On top of your view controller, add the gradient layer property:

var gradientLayer : CAGradientLayer!

Add the following to viewDidAppear func:

You can now build and run to see the results.
We are using green and blue at the moment so we can see clearly what’s going on.

Now, before we dive into animations, let’s try and put the green in the middle.
For that, we’ll need more than one gradient stop. We’ll need 3: Blue, green and blue again.

Add one more blue color to the colors array at index 0 , before the green color:

self.gradientLayer.colors = [UIColor.blue.cgColor, UIColor.green.cgColor, UIColor.blue.cgColor]

Build and run and you can see that we achieved what we aimed for.

CABasicAnimation

Core animation icon

For our animations, we’ll use CABasicAnimation.

I assume you know what CABasicAnimation is. If not, there are tons of guides on the web. I personally recommend reading Apple’s Core Animation Programming Guide.

In order to animate our gradient locations, we’ll need two arrays:

  • startLocations
  • endLocations

Add the startLocations property to your view controller:

var startLocations : [NSNumber] = [0.0,0.5,1.0]

Then, on your viewDidAppear func, add this line right before adding the layer to the view:

self.gradientLayer.locations = self.startLocations

If you run now, you’ll see, obviously, that the gradients remain the same.
That happens because the layer, as mentioned in the docs:

If nil, the stops are spread uniformly across the range.

Considering we had 3 values, that makes sense.

Start locations

If we look at what we did before, considering the green as our “moving gradient” effect, and we look at the animation again, we can see that it’s obviously not the start location of the animation.

The skeleton screen animation starts clear, without any gradient, and then the gradient is moving across the view horizontally.

For that, we will need to move our current gradient to the left until we don’t see the green. In order to do that we’ll need to set our starting points to a negative value.

Go ahead and decrease all our starting locations array values by 1. This will move the layer exactly to the point where can’t see it:

var startLocations : [NSNumber] = [-1.0,-0.5, 0.0]

End locations

What we need for our end locations is the exact same thing. We need the locations to be out of our bounds, too. But now, in the opposite direction. For that, we’ll need to copy our startLocations array, change it’s name to endLocations and shift all of it’s values by 2.0:

var endLocations : [NSNumber] = [1.0,1.5, 2.0]

If you run now, you will see only blue, and that’s good. We are in a good starting point for our animation.

Animate

In order to see our animation in action, let’s add a button to our view controller. Then connect it to an IBAction func.

Tapping this button will trigger our animation.

Add the following code to this func:

Run the project, and you will see that each time the button is pressed, the animation starts and ends where want it to.

We can now change the colors to look more like the skeleton view.
Before we do that, let’s add the “background” gradient color(Currently blue) and “moving” gradient(Currently green) as properties while we change their values:

var gradientBackgroundColor : CGColor = UIColor(white: 0.85, alpha: 1.0).cgColorvar gradientMovingColor : CGColor = UIColor(white: 0.75, alpha: 1.0).cgColor

Now, in viewDidAppear(), edit the colors assignment:

self.gradientLayer.colors = [   self.gradientBackgroundColor,   self.gradientMovingColor,   self.gradientBackgroundColor]

Run and you’ll see we are getting close.
This animation is kinda slow, though.

In the function triggered by the button action, set the duration of the animation to 0.8:

animation.duration = 0.8

Now we can add the following line in order to repeat the animation non-stop:

animation.repeatCount = .infinity

If you run now, you’ll see that the animation repeats immediately.
If you look at Facebook’s skeleton screen, you’ll see that there is a stop between animations.

One way we can achieve this is by using CAAnimationGroup.

CAAnimationGroup

As it sounds, this class groups CAAnimations together.
We can play with it’s duration value in order to make a “stop” between our animation loops.
We can achieve this by simply add more time to the group.

Declare a variable two new variables in ViewController:

var movingAnimationDuration : CFTimeInterval = 0.8var delayBetweenAnimationLoops : CFTimeInterval = 1.0

In animate(:), we can now remove the repeatCount from our animation to our animation group, and create an animation group. We can also make the animation look more natural and smooth by giving it a ease-in ease-out timing function.

Run and tap the animate button.

Separate

We don’t really need the controller to know that much about our view. The only thing the view controller needs is to tell the view when to animate and when to stop animating.

Create a new class that inherits from UIView, named ‘SkeletonView’, and move all the gradient animation code to it.
We can also add a function that stops the animation and end up with this custom view class:

You can now remove all the views and any code we wrote the view controller in order to try to imitate Facebook’s skeleton screen.

Mask

If you look at Facebook’s skeleton screens, you can see that all the views in the same cell share the same gradient.
It looks like the views act as a mask and the layer beneath is the layer with the animated gradient.

Masks are a different subject and I might write a post about this, too. But for now, you can see my final result:

You can grab the final project here.

It includes a view masking extension and some of the animations in the view controller.
Take a look at the view hierarchy in the storyboard file and the setup in the code.

Keep in mind that this is just the beginning of it. In order to achieve great UX you’ll have to do a bit more than that.

You can take what you have now and play with it for your own needs.
Create IBInspectable properties to the view, change it’s colors, durations, locations and such.

Leave any comment you like below :)

--

--