Animations challenges #1 — Bear iOS Search animation

Animations challenges is actually pretty fun. It’s about picking a random animation in one of the app that we use everyday ( twitter, Facebook, Slack, others .. ) and try to recreate it together by doing Pair Programming.

December 12 was the first day for me or John, both iOS Engineer at Eureka, for our Animations Challenges.

Animations are very funny. When you look at them, they look very simple, but when you try to look closer, you will notice that it involves many changes/sub-animations under the hood, making the end result amazing and almost unnoticed.

So the goal of those animations challenges is to try to analyse those animations and try to replicate them. After that, there will be a blog article showing how we approached this challenge.

Before diving into our first challenge, I would like to explain how we proceeed.

Process and conditions

Duration =~1hProcess: Pair programming and Pomodoro Technique

The Pomodoro Technique is about using a timer to break down work into interval. We try to switch every 15 minutes and allow each other to work on it.

It has great advantages, such as allowing both of us making technical decisions while the observer is asking questions making sure we are doing things right.

Introduction

The first animation we decided to reproduce within one hour was the search animation from the Bear iOS app.

Observation #2 — Scroll down to reach the goal

Animations happens when we scroll from top to bottom, which means that we have to:

Decide when the goal (final state) is reached. For exemple, after scrolling about 50 points vertically, it may means that we finished

Scrolling from top to bottom will generate a negative offset, so since we want to play with positive values, we cast it to a positive value

Since we are playing with a progress property, we want it to be between 0 and 1 ( 0% a and 100% )

And let’s add an empty search function for now

Observation #3 — Two search buttons?

Two different colors at the same time

When looking at it closer, we see that while scrolling, we can see two different stroke colors at the same time for the search icon.

So based on that, we supposed that:

There are maybe two buttons with the same size but different background and stroke color. The foreground button has a yellow dark background color with white stroke while the background button has a clear background color with a gray stroke

There is a mask (which can be a CAShapeLayer ) that hide/show a part of the foreground button.

As the user scroll, we are going to play with the mask path to show and hide the foreground button depending on the progress of the animation

So let’s fill our SearchView class now!

And then let’s layout everything:

Finally, let’s call the setup method when the view is initialized:

Observation #4 — Time to start filling

On the Observation #2, we created an empty update function.This function will take care of making this animation possible, and the first step is to start reproducing that “fill” animation

There is a mask (which can be a CAShapeLayer ) that hide/show a part of the foreground button.

The role of this mask layer is to show/hide the foreground button (the one with the yellow dark background color), based on the mask path, that’s how we can create this “fill” animation.

If the mask layer path is nil ( default value ), the view it’s associated with ( foreground button ) will not be visible. This is the case right now.

So let’s try to change this mask layer path properties based on the progress of the scroll and see what’s happening:

Filling from top to bottom

Wow! It start looking like something already! Let’s just tweak a little bit the starting point of this so that the animation start from the bottom to the top as we want, instead of the opposite.

Filling from bottom to top

We are almost there! Now we have to take care of the calling!

Observation #5 — Scaling to finish

Now that we can reach the full state, we need to make it to the final state when it’s scaled.

Let’s define how big we want the button to grow/scale, where 1.0 is the original size.

But there is one thing..Our update function is already using the progress property to change the mask’s path and fill the button completely when the progress is equal to 1.

But if we look at our animation states, the full state should be reached at 0.7, not 1.0. And from 0.7 to 1.0, it should play the scale animation..

So we have to tweak a little the progress property by shifting it from the interval 0…1 to 0…7.

How can we move from a range of 0…1 to 0…7 ?

Let’s apply some math:

(progress-newStartInterval) / (newEndInterval — newStartInterval)

(progress-0)/(0.7–0)

The new update function become:

Last and final step is to add the scaling feature. And there is another range shifting going on: we want to shift the progress from 0…1 to 0.7…1

Let’s apply some math again:

(progress-newStartInterval) / (newEndInterval — newStartInterval)

(progress-0.7)/(1–0.7)

So let’s add at the end of the update function the new shifted progress used for scaling the button:

So on the code below, if the progress is bigger than 0.7, then we start scaling based on the new shifted progress, otherwise, we remove the scaling effect;

Final Result

FInal animation (square)

Oh! And if you wanna have the rounded animation like the original animation, then you can make your button a circle:

FInal animation (circle)

✅ Good job for reading and reaching the end 💪

You can now reproduce a “similar” animation as the Bear iOS search application

You learned that sometimes, something that looks like a challenge, once putting enough through on it, can be achieved without struggling too much.

This is the first animation challenge blog article I write, and there is going to be more! So if you have any feedbacks, let me know :).