Reputation: 16829
How to set animation curve when using UIView's keyframe animation :
animateKeyframesWithDuration:delay:options:animations:completion:
Whatever I do in the animation block seems to be linear (unless I use the UIViewKeyframeAnimationOptionCalculationModeCubic
option but this isn't what I want).
I'd like to have an ease out curve on the animation like the UIViewAnimationOptionCurveEaseOut
option when using regular animation :
animateWithDuration:delay:options:animations:completion:
Upvotes: 21
Views: 17534
Reputation: 1107
Swift 2.0 will not allow casting of UIViewAnimationOptions
as UIViewKeyframeAnimationOptions
. It will also not allow |
ing them together.
However, there is an initializer for UIViewKeyframeAnimationOptions
that takes a rawValue
. So, the following code works to put UIViewAnimationOptions
into UIViewKeyframeAnimationOptions
:
let animationOptions: UIViewAnimationOptions = .CurveEaseOut
let keyframeAnimationOptions: UIViewKeyframeAnimationOptions = UIViewKeyframeAnimationOptions(rawValue: animationOptions.rawValue)
Then I can pass keyframeAnimationOptions
to animateKeyframesWithDuration
and everything works great.
For Swift 4:
let animationOptions = AnimationOptions.curveEaseOut
let options = KeyframeAnimationOptions(rawValue: animationOptions.rawValue)
Upvotes: 27
Reputation: 337
A simple way to set the animation curve for the keyframe animation is to wrap the keyframe animation inside the UIViewPropertyAnimator object:
let animator = UIViewPropertyAnimator(duration: 0.5, curve: .linear) {
// withDuration: 0 means inherited duration from UIViewPropertyAnimator
UIView.animateKeyframes(withDuration: 0, delay: 0, animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration:0.5) {
// modify view's properties
}
// more keyframes
})
}
animator.startAnimation()
Upvotes: 2
Reputation: 9352
The answer by @eskimwier did not work for me when trying to set the curve to linear
for animateKeyframes(withDuration:delay:options:animations:completion:)
. This was in Swift 3, Xcode 8.2.1.
My animation appeared to be defaulting to easeInOut
(slow start up, faster in the middle, slow at the end). Did Apple change the default curve?
Anyhow, I wanted a linear curve, and tried the approach suggested above to use UIViewAnimationOptions
with keyframe animations:
let animationOptions: UIViewAnimationOptions = .curveLinear
var keyframeAnimationOptions: UIViewKeyframeAnimationOptions = UIViewKeyframeAnimationOptions(rawValue: animationOptions.rawValue)
UIView.animateKeyframes(withDuration: 3, delay: 0, options: [keyframeAnimationOptions], animations: {
//... animations here ...
}, completion: nil)
This had no effect. The only thing that worked for me was to do this before calling animateKeyframes:
UIView.setAnimationCurve(UIViewAnimationCurve.linear)
Upvotes: 5
Reputation: 31486
Here's a nice and clean Swift solution I came up with:
extension UIViewKeyframeAnimationOptions {
init(animationOptions: UIViewAnimationOptions) {
rawValue = animationOptions.rawValue
}
}
Usage:
UIViewKeyframeAnimationOptions(animationOptions: .CurveEaseOut)
Upvotes: 11
Reputation: 131398
Actually, you can use the same curve flags that you use for animateWithDuration:delay:options:animations:completion:. Just "binary or" them in with the other options in your call to animateKeyframesWithDuration:delay:options:animations:completion:
The documentation is confusing, but it does work.
The curve values you can use are:
UIViewAnimationOptionCurveEaseInOut = 0 << 16,
UIViewAnimationOptionCurveEaseIn = 1 << 16,
UIViewAnimationOptionCurveEaseOut = 2 << 16,
UIViewAnimationOptionCurveLinear = 3 << 16,
The default animation curve you get is 0, or ease-in, ease-out.
Upvotes: 13
Reputation: 9977
If you are using keyframes, you have to define the curve on your own.. if you add linear keyframes, you have a linear animation. If you add non-linear keyframes, you will have a non-linear animation.
The frameStartTime
is your friend here... it will always be linear between keyframes (or paced / cubic / cubic paced, like defined in the UIViewKeyframeAnimationOptionCalculationMode
)
UIViewKeyframeAnimationOptionCalculationModeLinear = 0 << 9,
UIViewKeyframeAnimationOptionCalculationModeDiscrete = 1 << 9,
UIViewKeyframeAnimationOptionCalculationModePaced = 2 << 9,
UIViewKeyframeAnimationOptionCalculationModeCubic = 3 << 9,
UIViewKeyframeAnimationOptionCalculationModeCubicPaced = 4 << 9
To calculate correct timing values, you could use this as a reference: RBBEasingFunction
E.g. EaseInOutQuad
like this (where t is the relative time within the animation):
if (t < 0.5) {
return 2 * t * t;
} else {
return -1 + (4 - 2 * t) * t;
}
Upvotes: 2