为什么最终呈现的动画效果不尽如人意?
Why Is the Final Presentation of the Animation's Result Not What Is Expected?
以下 gif 演示了我遇到的动画问题。红色的小视图正在动画化。绿色的小视图标记了初始位置。红色视图动画向下和向右,然后自动反转。最后,回到初始位置后,红色视图向左跳转:就是这个跳转,我看不懂。
这是代码。动画分为两部分:Y 位置的初始变化和中途开始的 X 位置变化。两种动画都是自动反转的。请注意更新模型以反映由自动反转带来的最终视图位置的完成闭包。这一切对我来说似乎都是正确的。为什么向左跳?
@objc private func animate() {
let center = animationView.center
let distance: CGFloat = 100
let down = {
UIView.setAnimationRepeatAutoreverses(true)
self.animationView.center.y += distance
}
let right = {
UIView.setAnimationRepeatAutoreverses(true)
self.animationView.center.x += distance
}
let animator = UIViewPropertyAnimator(duration: 2, curve: .linear, animations: down)
animator.addAnimations(right, delayFactor: 0.5)
animator.addCompletion { _ in self.animationView.center = center } // Sync up with result of the autoreverse
animator.startAnimation()
}
- 向左的跳跃似乎是 100 点(与动画位置变化相同)
- 问题似乎与动画的第二部分有关。如果我不添加它而是在第一部分(修改 Y 的地方)修改 X 那么一切都很好。
- 当动画完成后,我检查红色视图的中心时发现它是 "correct";它等于根视图的中心。也就是说:模型和演示文稿不符???
- 当我使用 Xcode 的调试视图层次结构功能时,红色视图显示为位于屏幕中央
// ********************************************** ****************************
更新 #1:动画由两部分组成;向下和向右。在这两部分中,我都调用了 UIView.setAnimationRepeatAutoreverse。如果我注释掉其中一个或两个自动反转,那么一切都会按预期工作(尽管我没有得到自动反转的效果,但代码的行为是可以理解的)。
// ********************************************** ****************************
更新 #2:来自 Apple 的 UIView.setAnimationRepeatAutoreverse 文档:iOS 4.0 及更高版本不鼓励使用此方法。相反,您应该使用 animate(withDuration:delay:options:animations:completion:) 方法来指定动画和动画选项。
好的。让我们看看还有什么可以用来完成动画第二部分的延迟。
使用旧的API
@objc private func animate() {
let original = animationView.center
let distance: CGFloat = 100
let down = { self.animationView.center.y += distance }
let right = { self.animationView.center.x += distance }
let duration: TimeInterval = 2
UIView.animate(withDuration: duration, delay: 0, options: .autoreverse, animations: down) { _ in self.animationView.center.y = original.y }
UIView.animate(withDuration: duration/2, delay: duration/2, options: .autoreverse, animations: right) { _ in self.animationView.center.x = original.x }
}
终于来了!
private func animate() {
let distance: CGFloat = 100
let down = { self.animationView.center.y += distance }
let right = { self.animationView.center.x += distance }
let animator = UIViewPropertyAnimator(duration: 2, curve: .linear, animations: down)
animator.addAnimations(right, delayFactor: 0.5)
animator.pausesOnCompletion = true
let observer = animator.observe(\.isRunning, options: [.new] ) { animator, change in
print("isRunning changed to \(change.newValue!).")
if !animator.isRunning {
if !animator.isReversed {
print("Reversing animation")
animator.isReversed = true;
animator.startAnimation()
}
else {
print("Stopping animation")
animator.stopAnimation(false)
animator.finishAnimation(at: .start)
}
}
}
animator.addCompletion { position in
print("Animation completed at \(position). State = \(animator.state).")
observer.invalidate() // By capturing the observer here in the completion closure we keep it alive for the duration of the animation.
}
print("\nStarting animation")
animator.startAnimation()
print("Animation started")
}
以下 gif 演示了我遇到的动画问题。红色的小视图正在动画化。绿色的小视图标记了初始位置。红色视图动画向下和向右,然后自动反转。最后,回到初始位置后,红色视图向左跳转:就是这个跳转,我看不懂。
这是代码。动画分为两部分:Y 位置的初始变化和中途开始的 X 位置变化。两种动画都是自动反转的。请注意更新模型以反映由自动反转带来的最终视图位置的完成闭包。这一切对我来说似乎都是正确的。为什么向左跳?
@objc private func animate() {
let center = animationView.center
let distance: CGFloat = 100
let down = {
UIView.setAnimationRepeatAutoreverses(true)
self.animationView.center.y += distance
}
let right = {
UIView.setAnimationRepeatAutoreverses(true)
self.animationView.center.x += distance
}
let animator = UIViewPropertyAnimator(duration: 2, curve: .linear, animations: down)
animator.addAnimations(right, delayFactor: 0.5)
animator.addCompletion { _ in self.animationView.center = center } // Sync up with result of the autoreverse
animator.startAnimation()
}
- 向左的跳跃似乎是 100 点(与动画位置变化相同)
- 问题似乎与动画的第二部分有关。如果我不添加它而是在第一部分(修改 Y 的地方)修改 X 那么一切都很好。
- 当动画完成后,我检查红色视图的中心时发现它是 "correct";它等于根视图的中心。也就是说:模型和演示文稿不符???
- 当我使用 Xcode 的调试视图层次结构功能时,红色视图显示为位于屏幕中央
// ********************************************** ****************************
更新 #1:动画由两部分组成;向下和向右。在这两部分中,我都调用了 UIView.setAnimationRepeatAutoreverse。如果我注释掉其中一个或两个自动反转,那么一切都会按预期工作(尽管我没有得到自动反转的效果,但代码的行为是可以理解的)。
// ********************************************** ****************************
更新 #2:来自 Apple 的 UIView.setAnimationRepeatAutoreverse 文档:iOS 4.0 及更高版本不鼓励使用此方法。相反,您应该使用 animate(withDuration:delay:options:animations:completion:) 方法来指定动画和动画选项。
好的。让我们看看还有什么可以用来完成动画第二部分的延迟。
使用旧的API
@objc private func animate() {
let original = animationView.center
let distance: CGFloat = 100
let down = { self.animationView.center.y += distance }
let right = { self.animationView.center.x += distance }
let duration: TimeInterval = 2
UIView.animate(withDuration: duration, delay: 0, options: .autoreverse, animations: down) { _ in self.animationView.center.y = original.y }
UIView.animate(withDuration: duration/2, delay: duration/2, options: .autoreverse, animations: right) { _ in self.animationView.center.x = original.x }
}
终于来了!
private func animate() {
let distance: CGFloat = 100
let down = { self.animationView.center.y += distance }
let right = { self.animationView.center.x += distance }
let animator = UIViewPropertyAnimator(duration: 2, curve: .linear, animations: down)
animator.addAnimations(right, delayFactor: 0.5)
animator.pausesOnCompletion = true
let observer = animator.observe(\.isRunning, options: [.new] ) { animator, change in
print("isRunning changed to \(change.newValue!).")
if !animator.isRunning {
if !animator.isReversed {
print("Reversing animation")
animator.isReversed = true;
animator.startAnimation()
}
else {
print("Stopping animation")
animator.stopAnimation(false)
animator.finishAnimation(at: .start)
}
}
}
animator.addCompletion { position in
print("Animation completed at \(position). State = \(animator.state).")
observer.invalidate() // By capturing the observer here in the completion closure we keep it alive for the duration of the animation.
}
print("\nStarting animation")
animator.startAnimation()
print("Animation started")
}