Elegantly chaining UIViewPropertyAnimators
Usually my posts are mostly about design patterns, software architectures (or RxFlow š), but this time it will be different and frankly I didnāt think I would write about this kind of topic. But I think I have something cool to share: so today we are going to talk about Animations with Swift.
As usual you can find the original post on my personal blog (as well as other cool posts about Swift and software architecture): twittemb.github.io
Challenge accepted
I am not a UI/UX expert, so we are not going to dive into iOS animation frameworks, but lately I had a challenge to address at work. A colleague of mine came with this issue: āGuys, in our application we have some animations played in sequence and the way we do it is pretty ugly. Is there a better way ?ā.
UIView.animate()
The ugliness he was referring to is the way we traditionally chain animations with UIKit. To illustrate my point, letās consider this sequence:
Before iOS 10, one could have coded this sequence this way:
UIView.animate() provides a completion block we can use to trigger the next animation. Doing so, we can create a chain of animations. As you can see, the main drawback of this technic is the ugliness of the code. It is barely readable.
UIViewPropertyAnimator
Hopefully iOS 10 has introduced UIViewPropertyAnimator. I am not going to describe all the features it offers, there is a nice introduction here: useyourloaf.
What Iām concerned about is how to improve the readability of the chaining mechanism. First thing first, UIViewPropertyAnimator natively enhance the completion technic.
The previous code snippet would become:
It allows to clearly separate the definition of each animation from the way they are connected together.
Not only have we a far better readability but also a better decoupling. We could imagine chaining animations differently according to some context. Pretty neat.
But there is one more thing ā¦
Reactive animation chaining
I am a big fan of Reactive programming and the first thing that came to my mind was: Is there a way to make UIViewPropertyAnimation RxSwift compliant ?
What do we want to be aware of in a Reactive way ? pretty easy: the end of an animation, so we can trigger the next one.
Traditionally with RxSwift, making something compliant with reactive programming consists of adding an extension to the Reactive struct. That sounds like a good start.
We have to figure out what kind of extension we need and what should be the return type of this extension ?
The extension will somehow have to wrap the āstartAnimationā and āaddCompletionā mechanisms of UIViewPropertyAnimator. It will have to return some kind of Observable as well. But for the sake of simplicity, we will assume that an animation can only ācompleteā, there is no āstreamā management (such as onNext, onSubscribed, onDisposed and so on). This assumption has a nice consequence on our implementation. Our Reactive extension wonāt return an Observable but a Completable which is a Trait that implies the Observable can only be Completed (or failed).
Without further ado, letās see this extension:
Basically the āanimateā extension returns a Completable which, when being subscribed to, will start the animation and add a completion block that sends a ā.completedā event to the returned Completable.
The purpose is very simple: to be triggered when an animation is finished, so the next one can start.
The awesome thing with Completables is the ability to chain them with the very nice syntactic sugar expression āandThenā.
Letās see that in action:
It is very easy to read and is self explanatory. The animation sequence can even vary depending on some context, and the code structure is still very clear:
But wait, there is one last thing ā¦
Magic animation chaining
Although reactive chaining is quite satisfying, not everyone wants to rely on RxSwift to improve their code awesomeness !
Swift has a really cool feature to shorten complex statements while magnifying their expressivity: custom operators.
It takes some creativity to figure out the right way of doing this. So I asked myself what would be the most appropriate syntax for other developers to understand my code just by having a glance at it. I ended up with something like that :
animation1 ~> animation2 ~> animation3 ~> animation4
Could it be simpler ?
Letās do this:
What have we done here ?
- define a new binary operator: ~>
- define what is the behavior of this operator when applied to two UIViewPropertyAnimators
This is just a way to connect two UIViewPropertyAnimators together and to hook the start of the second one to the end of the first one.
Using this new syntax couldnāt be easier:
I am always amazed by the effectiveness Swift can bring to our coding flow. I used to be a Java guy, and believe me, having such a concise syntax is a relief.
I hope it will give you new ideas to go even further into chaining animations with Swift.
Stay tuned.