Skeleton view — alternative for loading indicator

Imagine this scenario:
- Client wants an app
- App has external API
- API is sending response
- Response comes after a while
- While data is loading we can’t build view
- View finally reloads with new data source

Who doesn’t know that? Many modern apps relies on some backend’s provided data. This means for us, that we have to wait for responses, which could take occasionally some time (at this moment I would like to say “Hi” some backend devs, oh, there’s a special place in hell for You!).
Anyway, it’s common practice to show loading indicator, started while view is loading, and then, after getting all the needed data, stop it. Simple solution for problems like that.

But what if we have situation when our whole view is just a bunch of cells in collection or table? We have this state where we can’t show empty page view placeholder, because obviously, we didn’t get response yet. Just like Schrödinger’s cat, view don’t know if it is empty or not. Showing prototyped cells with “title”, “subtitle” texts on labels looks bad. Blank page with spinner doesn’t looks good as well. What can we do to avoid showing view controller with lonely loading indicator?
OK, we can do a lot, but let’s assume that we don’t have time for writing Galaga game to entertain user (chapeau bas Namco, I will never forget ❤).

I would like to share with you some code for building SkeletonView!
The main idea is to show cells with animated overlay on labels, buttons and images. 
We can implement it in few steps, let’s dive into the code:

  1. Let’s create protocol which will implement show and hiding functions.
  2. Here we will provide default implementation of SekeletonDisplayable.
  3. Variables for naming skeleton layers.
  4. Function for searching proper view types.
  5. Finally, place where we will implement our function:
  • First we have to use skeletonViews(_:) to fill array with subviews. — Let’s create skeletonLayer which covers our whole main screen, it will be our mask for skeletons.
  • Create a loop where we will apply desired function for founded subviews
  • Next, mask our subview with skeletonLayer, add it as sublayer and finally add gradientLayer, which will be responsible for shimmering effect.
  • We have to animate our gradientLayer, it’s important to set animation.fromValue = -width, so the gradient will be pushed outside screen, we should also repeat it for .infinity with .fillMode = CAMediaTimingFillMode.forwards
  • Create a loop where we will apply desired function for founded subviews
  • Next, mask our subview with skeletonLayer, add it as sublayer and finally add gradientLayer, which will be responsible for shimmering effect.
  • We have to animate our gradientLayer, it’s important to set animation.fromValue = -width, so the gradient will be pushed outside screen, we should also repeat it for .infinity with .fillMode = CAMediaTimingFillMode.forwards

6. Function for removing skeleton layers from subviews

La grande finale! We’ve got all what we need we can run showSkeleton() method in viewDidAppear(_:).

After fetching data and building DataSource, we can simply stop it with stopSkeleton() method.

I hope you liked it, if you have any questions, feel free to contact me.

You can check implementation on GitHub: https://github.com/arturchabera/skeleton-view