swift 为什么UIKit在取消动画后计算错误的安全区域?

c7rzv4ha  于 2023-04-19  发布在  Swift
关注(0)|答案(1)|浏览(125)

有一个动画,它将视图从帧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,我该如何解决这个问题,使安全区域与动画取消后的视图帧相匹配?

jogvjijk

jogvjijk1#

这种行为不是UIKit中的bug。当您取消动画并将isReversed属性设置为true时,视图的帧将返回到其原始值
CGRect(x:10,y:10,宽度:100,高度:100)。
然而,视图的安全区域不受动画师的分数完成属性的影响,所以它仍然反映了动画结束时的值。要重置安全区域,您可以设置视图的约束以匹配其帧。我认为这部分将解决您的问题。

@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()
}

相关问题