I've just created a keyframe animation like this:
[UIView animateKeyframesWithDuration:10 delay:0 options:0 animations:^{
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:.1 animations:^{
view.alpha = 0;
}];
} completion:nil];
And this is a CAKeyframeAnimation
that gets created:
(lldb) po [self.layer animationForKey:@"opacity"]
<CAKeyframeAnimation:0x10a6364b0; keyTimes = (
0,
"0.1",
1
); values = (
1,
0,
0
); calculationMode = linear; delegate = <UIViewKeyframeAnimationState: 0x10a6358d0>; fillMode = both; timingFunction = easeInEaseOut; duration = 10; keyPath = opacity>
Question:
The entire animation should take 10 seconds with the opacity animating for 10 * 0.1 = 1 second, right? When I look at the animation, the change is being animated way longer than 1 second.
Why?
For an example of how keyframe intervals work, if your interval is set to every 2 seconds, and your frame rate is 30 frames per second, this would mean roughly every 60 frames a keyframe is produced.
For example, a key frame may be output once for each 10 seconds of video, even though the video image does not change enough visually to warrant the automatic creation of the key frame. That would allow seeking within the video stream at a minimum of 10-second intervals.
To insert a new frame, select Insert > Timeline > Frame (F5). To create a keyframe, select Insert > Timeline > Keyframe (F6), or right-click (Windows) or Control‑click (Macintosh) the frame where you want to place a keyframe, and select Insert Keyframe from the context menu.
In the upper-right corner of the Timeline in Motion, click the Show Keyframes button so that it's highlighted blue. Any applied keyframes appear in the track area as small red (or white, when selected) diamonds beneath the object they animate.
The reason is that the animation's timing function is not linear.
“Time and space are relative concepts.” – Theory of relativity
Layer and animations use a hierarchical timing system, where each object has its own local time which is dependant of its parents and its own timing parameters.
For instance, animations have a timing function that defines their pacing. The default timing functions for an animation created by UIKit is the ease-in ease-out timing function which defines a timing that begins slowly, accelerates through the middle of its duration, and then slows again before completing. It makes for smooth animations that don't start or stop abruptly. However it will also temper with the key times of your keyframe animation which is annoying when you need precise timing.
You can disable the ease-in ease-out timing by passing the UIViewAnimationOptionCurveLinear
option to the animateKeyframesWithDuration:delay:options:animations:completion:
method. I'm not sure whether it's intended as you need to cast the value from UIViewAnimationOptions
to UIViewKeyframeAnimationOptions
and the documentation does not say anything about that. Maybe a better (but more verbose) way is to embed the keyframe animation block inside a standard animation block like this:
[UIView animateWithDuration:10 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
[UIView animateKeyframesWithDuration:0 /*inherited*/ delay:0 options:0 animations:^{
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:.1 animations:^{
view.alpha = 0;
}];
} completion:nil];
} completion:nil];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With