Combine: The savior of iOS animation in Swift
Animation in iOS development
Generally, in order to build the fancy UI animation, iOS developers have to write a lot of code based on
which control the asynchronous animation flow by the completion handler.
In most scenarios, your code might look like
so… WELCOME TO THE CALLBACK HELL !
You might think that you can solve this problem by setting the delay interval of the animation block like
It seems like the callback hell has been eliminated and the mission accomplished.
However, some other issues emerged from the above code. What if we want to make the animation conditional, for example, the view will fade out only if it was faded in. Obviously you need some more code to save the result of the first animation, and determine whether to play the second one in its animation block. It’ll work, but in an ugly way, not to mention using the delay interval to control the flow will make the code fragile. Without further unit/ui testing, the animation could easily break down since a small change to the duration of the first animation.
Don’t panic first! All issues mentioned above are not kind of big news. There’re lots of third party framework try to help us solve these asynchronous control flow issues which you’ve probably used before.
If you are familiar with the frameworks above, you might find the code below easy to understand, even though I’m not using the framework above, the mindset remains the same. We’ve been focused on the problem for too long, time to find out the solution!
Solution
Combine is an official framework aimed to help developers manage the asynchronous data flow, it’s been documented well. Furthermore, you can find massive tutorials of Combine on the internet, so forgive me for skipping the introduction part.
Objectives:
- Support conditional animation.
- Stream base animation flow instead of completion handler.
- Looked cool 😎
Preflight: Make sure you’re familiar with the concept of reactive programming
In Combine, those objects deliver new elements are called Publisher. The first step is creating our animation publisher who will deliver a boolean once the animation completed, which means this publisher will pass only one element to the down stream and I’ve already found my ideal Publisher in this scenario.
Wrap the animation functions in Future
You can create your animation like
It works like a charm 😉 😘. How about something more tricky.
Conditional animation, CHECKED ✅!
Walk through
Let’s walk through the code step by step
First, we fire up the first stage of our animation which will spend 1.5 seconds moving the cube from left top to the center of the view and spend 0.5 seconds changing the background color from red to blue and making the cube bigger at the same time. We prepend a false to both publishers as the initial state.
Second, we’ll play the C animation once the animations in first stage triggered, play the B animation right after the second animation finished, and play the A animation after step one finished.
At last, print “animation finished” to the console as a perfect ending.
Conclusion
You might think that the conditional animation is a little bit useless, but it becomes handy while you have to clean up once your animation is cancelled (usually by another animation or modification of the view hierarchy). And the real power of Combine + UIView.animate is that we can concatenate animations in a declarative way, and easily branch out or merge the animation flow.