如何将 AutoLayout 与变换结合使用

Fra*_*eng 5 ios autolayout

苹果文档中写道:

\n\n
\n

在 iOS 8.0 及更高版本中,transform 属性不会影响自动布局。自动布局根据其未变换的框架计算视图\xe2\x80\x99s 对齐矩形。

\n
\n\n

因此,如果我有一个名为的视图View1,该视图通过使用变换属性进行缩放,并且View2想要与 的边缘对齐View1。我该如何使用 来做到这一点AutoLayout

\n

bad*_*esh 4

好问题。正如您所引用的,约束适用于视图的原始未转换边界。

\n\n

为了能够使您的其他视图尊重变换后的边界,一种方法是在应用变换后计算约束常量的偏移量。下面是与您的情况类似的示例,但具有顶部约束,而不是前导/尾随/对齐。但基本上您也可以对其他情况应用相同的程序。

\n\n

目前这有效,请随意改进这个答案。

\n\n
\n\n

故事板设置:

\n\n

故事板设置

\n\n

应用变换后的输出(scaleX:3, scaleY:2.5)

\n\n

\n\n
\n\n

我们在下面的代码中所做的是:

\n\n
    \n
  1. IBOutlet约束的构成。
  2. \n
  3. 将约束的原始常量存储到变量中。
  4. \n
  5. 应用之前存储要缩放的视图框架。
  6. \n
  7. 应用变换。
  8. \n
  9. 存储变换后的视图框架。
  10. \n
\n\n

注意:根据苹果文档,它说:

\n\n
\n

警告
\n 当此属性的值不是恒等变换时,框架属性中的值未定义,\n 应被忽略。

\n
\n\n

但转换后的框架似乎在应用比例后立即可用。因此我们将其保存到变量中以供将来使用。如果您尝试访问其他位置的帧,您将无法获得正确的帧。因此,我们在应用变换后立即执行此步骤。

\n\n
    \n
  1. 通过重写updateViewConstraints视图控制器的方法,您有机会更新约束。现在我们只需获取两个框架底部位置的差异并将其应用于 的约束常数IBOutlet
  2. \n
\n\n
\n\n
import UIKit\n\nclass ViewController: UIViewController {\n\n    @IBOutlet weak var view1: UIView! //Dark gray view\n    @IBOutlet weak var view2: UIView! //Light gray view\n\n    @IBOutlet weak var topConstraint: NSLayoutConstraint!\n\n    let transformScaleX:CGFloat = 3\n    let transformScaleY:CGFloat = 2.5\n\n    var rectBeforeTransform:CGRect = .zero\n    var rectAfterTransform:CGRect = .zero\n\n    var originalTopConstraintConstant:CGFloat = 0\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        //Store original constraint value\n        self.originalTopConstraintConstant = self.topConstraint.constant\n        //Store unaltered frame of the view\n        self.rectBeforeTransform = view1.frame\n        //Apply transform\n        self.view1.transform = .init(scaleX: transformScaleX, y: transformScaleY)\n        //Frame after transform.\n        //NOTE: When a non-identity transform is applied to a view, its frame is undefined, so we would not get proper frame info. of the view anywhere other than after applying the tranform.\n        self.rectAfterTransform = view1.frame\n    }\n\n    override func updateViewConstraints() {\n        DispatchQueue.main.async {\n            let constraintOffset = abs(self.rectAfterTransform.bottomY - self.rectBeforeTransform.bottomY)\n            self.topConstraint.constant = self.originalTopConstraintConstant + constraintOffset\n        }\n        super.updateViewConstraints()\n    }\n\n}\n\nextension CGRect {\n    var bottomY:CGFloat {\n        get {\n            return self.height + self.origin.y\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

PS:当前的答案仅适用于顶部约束,我将尝试更新所有前导/尾随/顶部/底部约束的答案,以及可能的更优雅的解决方案。至于动画,不幸的是我\xe2\x80\x99m无法提供通过的方法。如果我找到一些会更新。谢谢。

\n\n
\n