可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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:
回答1:
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;
}
回答2:
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.
回答3:
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.
回答4:
Here's a nice and clean Swift solution I came up with:
extension UIViewKeyframeAnimationOptions {
init(animationOptions: UIViewAnimationOptions) {
rawValue = animationOptions.rawValue
}
}
Usage:
UIViewKeyframeAnimationOptions(animationOptions: .CurveEaseOut)
回答5:
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)