我想实现一个动画:每个单元格 rightImage 首先移动,在 rightImage 移动后,背景图像(这是一个 gif)开始动画。但是,移动动画和 gif startAnimating 总是同时开始。就像下面的演示:
这是打印移动时间戳和动画时间戳的调试日志:
<<< start index: 0
>>> start transfrom 2023-04-04 10:32:39
>>> start animating 2023-04-04 10:32:39
<<< start index: 1
>>> start transfrom 2023-04-04 10:32:43
>>> start animating 2023-04-04 10:32:43
<<< start index: 2
>>> start transfrom 2023-04-04 10:32:47
>>> start animating 2023-04-04 10:32:47
这是我的动画代码:
func startMoving() {
let duration: Double = 4
UIView.animateKeyframes(withDuration: duration, delay: 0, options: [.calculationModeLinear], animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.7/duration, animations: {
print(">>> start transfrom")
self.frontImageView.transform = CGAffineTransform(translationX: -20, y: 0)
})
UIView.addKeyframe(withRelativeStartTime: 0.7/duration, relativeDuration: 1.5/duration, animations: {
print(">>> start animating")
self.backgroundImageView.startAnimating()
})
}, completion: { _ in
self.backgroundImageView.stopAnimating()
})
}
几件事...
1 - 您错误地使用了相对开始时间和相对持续时间 2 - 关键帧动画并不像你想象的那样工作
相对时间是持续时间的百分比。
如果您希望第一个关键帧立即开始,并运行总持续时间的 70%,它应该如下所示:
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.7, animations: {
并且您希望第二个关键帧在第一个动画结束时开始(因此,从开始开始的 70%),然后运行剩余部分:
UIView.addKeyframe(withRelativeStartTime: 0.7, relativeDuration: 0.3, animations: {
所以,让我们更改计时参数,并添加更多
print()
语句:
func startMoving() {
let duration: Double = 4
UIView.animateKeyframes(withDuration: duration, delay: 0, options: [.calculationModeLinear], animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.7, animations: {
print(">>> start transfrom")
self.frontImageView.transform = CGAffineTransform(translationX: -20, y: 0)
})
UIView.addKeyframe(withRelativeStartTime: 0.7, relativeDuration: 0.3, animations: {
print(">>> start animating")
self.backgroundImageView.startAnimating()
})
}, completion: { _ in
print(">>> completion")
self.backgroundImageView.stopAnimating()
})
print(">>> end of startMoving()")
}
您将在调试控制台中看到的是立即:
>>> start transfrom
>>> start animating
>>> end of startMoving()
在 4 秒结束时:
>>> completion
但是,您仍然会看到动画从零开始。
关键帧动画 not 等待执行代码。在
UIView.animateKeyframes
块内,UIKit 立即分析所有addKeyFrame
片段,然后“播放动画”
这就是为什么生成的动画会根据 KeyFrameAnimationOptions
(
.calulationMode...
值)看起来不同的原因。逻辑上,我们
认为这一行:self.backgroundImageView.startAnimating()
将在总持续时间的70%时执行。实际上,它在UIKit构建动画时执行,这就是为什么你的图像视图动画从开始开始. 如果你想让“前”视图滑过,然后
然后启动图像视图动画,你需要播放滑过动画并在完成后启动图像视图动画。
沿着这些线的东西:
func startMoving() {
let duration: Double = 4.0 * 0.7
UIView.animate(withDuration: duration, animations: {
print(">>> start transfrom")
self.frontImageView.transform = CGAffineTransform(translationX: -20, y: 0)
}, completion: { _ in
print(">>> start animating")
// maybe set imageView animation properties...
self.backgroundImageView.animationRepeatCount = 1
self.backgroundImageView.animationDuration = 1.0 // 1-second to cycle through all images
self.backgroundImageView.startAnimating()
})
print(">>> end of startMoving()")
}