在 viewWillAppear 中设置约束

Setting Constraints in viewWillAppear

我在viewcontroller中间有一个uiview。这个uiview.

上面(A)下面有一个uilabel

我想以编程方式更改此 uiview 的底部约束,以便随着屏幕尺寸的变化,uiview 上方和下方的距离彼此相等。所以计算顶部 uiviewuilabel 底部的距离 (A) 和底部 uiviewuilabel 顶部的距离 (B),除以 2 然后设置相应的底部约束常数。

我已经完成了计算,但它似乎只有在我将它放在 viewDidAppear 中时才有效,并且我需要在用户能够看到对象之前将约束和视图放在正确的位置。这可以在 viewWillAppear 中完成吗?感觉所有元素直到 viewDidAppear 才设置好让我正确计算..我相信这与 autolayout 的生命周期有关,在计算之前未完成..

let topDistance = view.frame.minY - ALabel.frame.maxY
    let bottomDistance = BLabel.frame.minY - view.frame.maxY
    let total = topDistance + bottomDistance
    bottomConstraint.constant = total / 2

下面是所需结果的 before/after 示例,其中紫色 uiview 对底部橙色 uilabel 具有底部约束。例如,当屏幕尺寸增加时,我希望底部约束与紫色 uiview 和顶部橙色 uilabel 之间的距离具有相同的常数。顶部 uilabel 对顶部有顶部约束,底部 uilabel 对底部有底部约束。

更新约束后写入layoutIfNeeded

let topDistance = view.frame.minY - ALabel.frame.maxY
let bottomDistance = BLabel.frame.minY - view.frame.maxY
let total = topDistance + bottomDistance
bottomConstraint.constant = total / 2
self.view.layoutIfNeeded()

当您使用 View 时,用户已经看到 VeiwController, 请改用 viewDidLoad ,您不能使用 viewWillAppear ,因为尚未加载视图。

用于:

override func viewDidLoad() {
    super.viewDidLoad()
}

你可以试试打电话给

self.view.layoutIfNeeded()

当我想以编程方式设置约束时,我通常会这样进行:

let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
v.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20).isActive = true
v.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20).isActive = true
v.heightAnchor.constraint(equalToConstant: 100).isActive = true
v.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor).isActive = true

您可以为此使用 Dispatch Queue:

      DispatchQueue.main.async {
          let topDistance = view.frame.minY - ALabel.frame.maxY
          let bottomDistance = BLabel.frame.minY - view.frame.maxY
          let total = topDistance + bottomDistance
          bottomConstraint.constant = total / 2
         self.view.layoutIfNeeded()
    }

尝试回答您的问题:

你是对的,自动布局在 viewDidLoad() 甚至 viewWillAppear() 中都没有完成它的工作。通常,当您需要进行这样的布局调整时,您希望在 viewDidLayoutSubviews() 中进行。来自 Apple 的文档:

viewDidLayoutSubviews

When the bounds change for a view controller's view, the view adjusts the positions of its subviews and then the system calls this method.

但是,如果我理解您实际想要做什么...

通过使用 UIStackView,您可以避免使用 任何 代码。

将您的标签、视图、按钮等嵌入垂直 UIStackView。将属性设置为:

Alignment: Fill   (or Leading or Center as suits your layout)
Distribution: Equal Spacing
Spacing: 0

将堆栈视图的顶部约束到视图的顶部(加上任何所需的填充)并将底部约束到视图的底部(加上任何所需的填充)。

iPhone SE 大小的结果:

iPhone 8 尺寸的结果:

iPhone XS 码的结果:

还有,这里是 iPhone 8,还有一些不同高度的附加元素:

如您所见,元素之间的垂直间距相等,并且全部由堆栈视图处理。