JTSSwiftTweener: Animating arbitrary numeric properties

UIView.animate() and CoreAnimation provide an excellent framework for animating changes to visual properties of views in iOS. However, what if you want to animate a non-visual numeric property? Some examples might be:

  • Animate the properties of a CIFilter.
  • Animate a number changing within a label.
  • Animate ANYTHING which isn’t a UIView or CALayer property.

There are some hacky solutions you can do such as making a custom CALayer subclass which uses a delegate callback to report the setting of some property. However, this is cumbersome to set up and maintain, so I created my own tweening library to fill in the gap.

How it works

Tweener is a fairly simple class. It has static methods for creating tweens as well as pausing and resuming animation. At it’s core is a CADisplayLink which provides “ticks” that drive the animation. The core measures the elapsed time since the last tick and advances each of its child animations by that amount. This approach allows animation to finish in constant time, even when the frame rate is fluctuating.

When the Tweener.tween(...) method is called, a new instance of Tweener is created and returned. Simultaneously, it is added to the internal array of managed instances so that it can receive ticks. If the CADisplayLink is paused, it is unpaused.

With each tick, the individual Tweener instances are told how much time has elapsed. They, in turn, calculate how far along through their duration they are and update their progress closures appropriately. If a Tweener instance determines that elapsed time has equaled or exceeded its duration, it calls its completion closure (if it has one) and flags itself as complete. At the end of every tick, the Tweener class scans its instances and removes the completed ones. If the number of active instances is reduced to zero, then the CADisplayLink is paused.

There is only one class file to include in your project, available here.

I also have a very simple example project for you to look at.

What’s next?

The two primary areas for improvement are:

  1. Performance – It seems to work pretty well, but I’ve not done extensive testing on the tick methods to ensure maximum efficiency.
  2. Additional Easing Functions – I only have two Easing families at the moment. There are dozens of variations documented online (see here), and adding a few more to the class would improve its flexibility.