CGAffineTransform 弄乱了 ViewFrame

CGAffineTransform messing up ViewFrame

我有一个 UIViewControllerAnimatedTransitioning,其中一个动画是使用 CGAffineTransform

的比例尺
toView.frame.origin.y = containerView.frame.size.height - toView.frame.height
fromView.transform = CGAffineTransform(scaleX: 0.96, y: 0.94)
fromView.frame = fromView.frame.offsetBy(dx: 0, dy: self.topOffset)

这让我的帧从 (0.0, 0.0, 375.0, 667.0)(7.5, 20.00999999999999, 360.0, 626.98),在返回的路上:

toView.transform = CGAffineTransform.identity
toView.frame = toView.frame.offsetBy(dx: 0, dy: -self.topOffset)
fromView.frame.origin.y = containerView.frame.size.height

问题是:框架没有回到原来的状态,而是搞砸了,现在我得到:0.0, -5.684341886080802e-14, 375.0, 667.0000000000001),主要问题当然是 y 定位。

请注意值 self.topOffset 为 0,我已尝试删除此行,但没有任何结果。

第一个片段中的 fromView 是第二个片段中的 toView

如果您想查看该函数的完整代码:

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let fromViewController = transitionContext.viewController(forKey: .from),
            let toViewController = transitionContext.viewController(forKey: .to),
            let toView = toViewController.view,
            let fromView = fromViewController.view,
            let containerView = containerView else { return }


        let isPresenting = fromViewController == presentingViewController
        if isPresenting {
            toView.frame.origin.y = fromView.frame.size.height
        }

        UIView.animate(withDuration: transitionDuration(using: transitionContext),
                       delay: 0,
                       usingSpringWithDamping: 1,
                       initialSpringVelocity: 0,
                       options: .curveEaseInOut,
                       animations: {
            if isPresenting {
                toView.frame.origin.y = containerView.frame.size.height - toView.frame.height
                fromView.transform = CGAffineTransform(scaleX: 0.96, y: 0.94)
                fromView.frame = fromView.frame.offsetBy(dx: 0, dy: self.topOffset)
            }
            else {
                toView.transform = CGAffineTransform.identity
                toView.frame = toView.frame.offsetBy(dx: 0, dy: -self.topOffset)
                fromView.frame.origin.y = containerView.frame.size.height
            }
        }) { (finished) in
            if finished {
                transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
            }
        }
    }

顺便说一句,将初始值保留在变量上并在之后设置它可以解决问题,但这似乎是一种变通方法而不是解决方案。我想了解为什么会发生这种情况以及是否有更好的方法。

以下是我认为可能有误的地方。从 Docs 到 UIView 框架,

If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.

你不应该在设置转换后使用框架 属性。相反,如文档中所述,

Changes to this property can be animated. However, if the transform property contains a non-identity transform, the value of the frame property is undefined and should not be modified. In that case, reposition the view using the center property and adjust the size using the bounds property instead.

所以

fromView.frame = fromView.frame.offsetBy(dx: 0, dy: self.topOffset)

需要修改为

fromView.center = fromView.frame.center + self.topOffset
fromView.frame = fromView.frame.bounds

但我认为我们不需要修改 toView 代码,因为我们在设置框架之前将 transform 设置为 Identity。


根据上面所说,解决问题的方法是修改第一个块:

toView.frame.origin.y = containerView.frame.size.height - toView.frame.height
fromView.transform = CGAffineTransform(scaleX: 0.96, y: 0.94)
fromView.frame = fromView.frame.offsetBy(dx: 0, dy: self.topOffset)

toView.frame.origin.y = containerView.frame.size.height - toView.frame.height
fromView.frame = fromView.frame.offsetBy(dx: 0, dy: self.topOffset)
fromView.transform = CGAffineTransform(scaleX: 0.96, y: 0.94)

基本上在应用变换之前进行帧重新定位。