首页 > 解决方案 > CGAffineTransform 弄乱了 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)
            }
        }
    }

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

标签: swiftcore-animationuiviewanimationcgaffinetransformuiviewanimationtransition

解决方案


这是我认为可能是错误的。从UIView 框架上的文档,

如果变换属性不是恒等变换,则该属性的值是未定义的,因此应该被忽略。

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

对此属性的更改可以设置动画。但是,如果 transform 属性包含非恒等变换,则 frame 属性的值是未定义的,不应修改。在这种情况下,使用 center 属性重新定位视图并使用 bounds 属性调整大小。

所以

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)

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


推荐阅读