Syncing UIView animations

Christoffer Winterkvist
itch design
Published in
3 min readFeb 13, 2018

I was building a child view controllers framework recently and while implementing animations, I stumbled across a fairly regular issue with iOS development. I was trying to sync two animations, the thing that made it less trivial was not directly applied with core animation but was implemented using a regular UIView animation with an animation closure. To make matters worse, because the component was developed as a framework the solution had to be devoid of strong ties.
Luckily I found a solution that I’d love to share with you.

To give you some more context, the problem that I was trying to solve was the frameworks layout algorithm. I wanted to provide the user of the framework full control over the view hierarchy, giving them the option to apply animation when expanding, collapsing or merely hiding UI components. The first step was simply running the algorithm in an animated context.

I went with the most straightforward approach which was to wrap the algorithm in a UIView animation closure and giving the animation the options to start from its current state and to allow user interactions. The latter was added to not disrupt the users scrolling experience.

So far everything was fine, but when I started testing different scenarios, I quickly realized that animations were out-of-sync. If the animation duration did not match the duration that the framework used, they could never match.
This is what the client-side code looked like:

If you look closely, you can see that the duration of the framework and the client-side application is out-of-sync, mainly because the user wants another value than the framework default.

From the genesis of the framework, I wanted to keep the API as simple as possible, and what is more straightforward than something that you never even have to learn. I thought I hit a roadblock and would be left with implementing another method to properly transition to a new state.

After some investigation and deep thought about what UIView animation is, I came up with a solution.

A UIView animation is a convenience abstraction on top of core animation, which meant that these could be resolved by asking the layer for its animation keys. For the case that I tried to solve, I could simply query the views that I monitor to know if any of them have animations tied to them.

That would decide if the layout algorithm would run using animations or if the results should render without delay.

So with the knowledge of which animation keys were in play, I could extract the animation and inspect its values. For frame animations, I ended up getting a `CABasicAnimation`. Because `CABasicAnimation` inherits from `CAAnimation` which in turn conforms to `CAMediaTiming`, I could make use of the duration property which is what I wanted.

I wrapped it all up in a small extension on `CALayer`, it’s not a thing of beauty, but it works.

https://github.com/zenangst/Family/blob/master/Sources/iOS%2BtvOS/Extensions/CALayer%2BExtensions.swift

In my case, I just care about the first animation and its duration, so I ended up with this as my implementation in the framework:

https://github.com/zenangst/Family/blob/master/Sources/iOS%2BtvOS/Classes/FamilyScrollView.swift#L250-L257

I bet you guys and gals can apply this to more advanced cases, but this approach helped solve the issue I was facing, hope you find this useful, it was an eye-opener for me.

--

--

Christoffer Winterkvist
itch design

random hero at @fink-oslo by day, cocoa vigilante by night, dad at dawn. my life is awesome. Previously @hyperoslo