有一个动画,动画视图从帧CGRect(x: 10, y: 10, width: 100, height: 100)
到帧CGRect(x: 10, y: 10, width: 300, height: 300)
。我使用UIViewPropertyAnimator来实现动画,下面是代码:
@objc func onTap() {
animator = UIViewPropertyAnimator(duration: 3, curve: .easeIn)
animator.addAnimations {
self.testView.frame = CGRect(x: 10, y: 10, width: 300, height: 300)
}
animator.addCompletion { pos in
print("test view frame:::", self.testView.frame)
print("test view safe frame:::", self.testView.safeAreaLayoutGuide.layoutFrame)
print("test view safe inset:::", self.testView.safeAreaInsets)
print("test view keyboard frame:::", self.testView.keyboardLayoutGuide.layoutFrame)
}
animator.startAnimation()
}
在动画过程中,还有一个按钮用于暂停动画和取消动画,代码如下:
@objc func cancelTheAnimation() {
animator.pauseAnimation()
animator.isReversed = true
let progress = animator.fractionComplete
animator.continueAnimation(
withTimingParameters: UICubicTimingParameters(animationCurve: .linear),
durationFactor: 1 - progress)
}
下面是控制台打印
的结果------- animation completion ------
test view frame::: (10.0, 10.0, 100.0, 100.0)
test view safe frame::: (0.0, 37.0, 100.0, 63.0)
test view safe inset::: UIEdgeInsets(top: 37.0, left: 0.0, bottom: 0.0, right: 0.0)
test view keyboard frame::: (-10.0, 100.0, 390.0, 734.0)
------- animation completion ------
test view frame::: (10.0, 10.0, 100.0, 100.0)
test view safe frame::: (0.0, 37.0, 300.0, 263.0)
test view safe inset::: UIEdgeInsets(top: 37.0, left: 0.0, bottom: 0.0, right: 0.0)
test view keyboard frame::: (-10.0, 300.0, 390.0, 534.0)
结果第一次是正确的。然而,当我第二次取消动画时,结果是错误的,它应该是100而不是300(263 + 37)。
动画取消后,视图的帧被重置回其初始值,但安全区布局指南仍然是完成动画时设置的目标值。
这是UIKit的bug吗?
如果这不是UIKit的bug,我怎么解决这个问题,使安全区域与视图的帧匹配后取消动画
这个行为不是UIKit的bug。当您取消动画并将isReversed属性设置为true时,视图的框架将返回到其原始值
CGRect(x: 10, y: 10, width: 100, height: 100).
然而,视图的安全区域不受动画师的fraction complete属性的影响,因此它仍然反映动画结束时的值。要重置安全区域,您可以将视图的约束设置为与其框架匹配。我想这部分可以解决你的问题。
@objc func cancelTheAnimation() {
animator.pauseAnimation()
animator.isReversed = true
let progress = animator.fractionComplete
animator.continueAnimation(
withTimingParameters: UICubicTimingParameters(animationCurve: .linear),
durationFactor: 1 - progress)
testView.translatesAutoresizingMaskIntoConstraints = true
testView.frame = CGRect(x: 10, y: 10, width: 100, height: 100)
testView.layoutIfNeeded()
}