Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding animateKeyframes relative start times/delays

Tags:

ios

swift

I'm either being stupid, or misunderstanding how keyframe animations work on iOS (or both!). The two animation blocks below produce different results but I would expect them to be the same:

let duration: TimeInterval = 2

UIView.animateKeyframes(withDuration: duration, delay: 0, animations: {
    UIView.addKeyframe(withRelativeStartTime: 0.9, relativeDuration: 0.1, animations: {
        self.someView.transform = CGAffineTransform(translationX: 0, y: 150)
    })
})

UIView.animateKeyframes(withDuration: duration * 0.1, delay: duration * 0.9, animations: {
    UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1, animations: {
        self.someView.transform = CGAffineTransform(translationX: 0, y: 150)
    })
})

Can anyone help me understand why these are different when executed? The first seems to do what I expect, but the second one seems to execute the animation earlier than expected.

like image 473
Ian L Avatar asked Dec 14 '17 13:12

Ian L


1 Answers

You're seeing the effects of the default timing curve on your keyframe animations. The first animation is the last 0.2 seconds of a 2 second animation, and the second animation is the entirety of a 0.2 second animation. The default ease-in-ease-out means that the first animation will be done entirely in the ease-out portion of the curve.

To force a linear curve on both animations you can wrap them inside another animation and set a couple of options:

UIView.animate(withDuration: duration, delay: 0, options: [.curveLinear], animations: {
    UIView.animateKeyframes(withDuration: duration, delay: 0, options: [.overrideInheritedDuration, .calculationModeLinear], animations: {
        UIView.addKeyframe(withRelativeStartTime: 0.9, relativeDuration: 0.1, animations: {
            view1.transform = CGAffineTransform(translationX: 0, y: 150)
        })
    })

    UIView.animateKeyframes(withDuration: duration * 0.1, delay: duration * 0.9, options: [.overrideInheritedDuration, .calculationModeLinear], animations: {
        UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1, animations: {
            view2.transform = CGAffineTransform(translationX: 0, y: 150)
        })
    })
}, completion: nil)

Which I think you'll agree is horrible-looking code, but I'm assuming this is an intellectual exercise :)

like image 195
jrturton Avatar answered Oct 06 '22 01:10

jrturton