Atelier Clockwork

Working With Keyframes

Where Type Safety Gets in the Way

Working with advanced animations is always a bit of a challenge, and when working on a keyframe based animation, I couldn't figure out how to get the entire animation to run in a linear fashion, and it took some digging on Stack Overflow to get on the right track. Without type safety the answer was to add the UIViewAnimationOption value to the UIViewKeyframeAnimationOption value. With type safety, it takes getting clever with raw values.

First I checked if all of the UIViewAnimationOption flags were supported by keyframe animations, at at a glance it looks like the answer is that some of them are ignored if applied to a keyframe animation. That meant that just writing an initializer that crammed to two values together wasn't a great plan.

After a bit of digging, I ended up writing this:

public extension UIViewKeyframeAnimationOptions {
    // This exists because keyframe options doesn't expose the easing for the overall curve
    public init(keyframeAnimationsOptions: UIViewKeyframeAnimationOptions, animationCurve: UIViewAnimationCurve) {
        let animationOptions: UIViewAnimationOptions
        switch animationCurve {
        case .EaseIn: animationOptions = .CurveEaseIn
        case .EaseInOut: animationOptions = .CurveEaseInOut
        case .EaseOut: animationOptions = .CurveEaseOut
        case .Linear: animationOptions = .CurveLinear
        }
        self = UIViewKeyframeAnimationOptions(rawValue: keyframeAnimationsOptions.rawValue | animationOptions.rawValue)
    }
}

That consumes a UIViewKeyframeAnimationOption and a UIViewAnimationCurve value, and inserts the correct value for the animation curve into the UIViewKeyframeAnimationOption set. It's still mashing raw values together under the hood, there's no getting around that, but that's well encapsulated and only valid sets of raw values can be mashed together.