在 viewWillAppear 中设置约束
Posted
技术标签:
【中文标题】在 viewWillAppear 中设置约束【英文标题】:Setting Constraints in viewWillAppear 【发布时间】:2019-02-21 09:21:14 【问题描述】:我在viewcontroller
的中心有一个uiview
。在此uiview
上方(A)和下方(B)有一个uilabel
。
我想以编程方式更改此uiview
的底部约束,以便uiview
上方和下方的距离随着屏幕尺寸的变化而彼此相等。因此,计算顶部uiview
到uilabel
底部之间的距离(A)和底部uiview
到uilabel
顶部之间的距离(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
下面是所需结果的前/后示例,其中紫色uiview
对底部橙色uilabel
具有底部约束。例如,当屏幕尺寸增加长度时,我希望底部约束与紫色uiview
和顶部橙色uilabel
之间的距离具有相同的常数。顶部uilabel
对顶部有一个顶部约束,底部uilabel
对底部有一个底部约束。
【问题讨论】:
请添加您想要的图片。 我认为你想要的东西可以在没有计算的情况下设置,只使用静态约束。 您的描述不是很清楚。您有 3 个元素:TopLabel
(T)、CenterView
(CV)、BottomLabel
(B),垂直对齐MainView
(MV),对吗?并且您希望从MV
的顶部到T
的顶部的垂直间距相等; T
的底部到 CV
的顶部; CV
的底部到 B
的顶部;和B
的底部到MV
的底部?对吗?
@MayurKarmur 我已经添加了图片和解释,这有助于澄清更多吗?
@Chris - 抱歉,还是有点混乱。 TopLabel
被限制在 MainView
的顶部?而BottomLabel
被限制在MainView
的底部?如果是这样,那么不要将 Purple 限制为任一标签...只需将其限制为 centerY
【参考方案1】:
尝试回答您的问题:
你说得对,自动布局在viewDidLoad()
甚至viewWillAppear()
中还没有完成它的工作。通常,当您需要进行这样的布局调整时,您希望在viewDidLayoutSubviews()
中进行。来自 Apple 的文档:
viewDidLayoutSubviews
当视图控制器视图的边界发生变化时,视图会调整其子视图的位置,然后系统调用此方法。
但是,如果我了解您实际上想要做什么...
通过使用UIStackView
,您可以避免使用任何代码。
在 Vertical UIStackView
中嵌入您的标签、视图、按钮等。将属性设置为:
Alignment: Fill (or Leading or Center as suits your layout)
Distribution: Equal Spacing
Spacing: 0
将堆栈视图的顶部约束到视图的顶部(加上任何所需的填充)和底部到视图的底部(加上任何所需的填充)。
iPhone SE 尺寸结果:
iPhone 8 尺寸的结果:
iPhone XS 尺寸的结果:
还有,这是 iPhone 8,带有几个不同高度的附加元素:
如您所见,元素之间的垂直间距相等,并且全部由堆栈视图处理。
【讨论】:
堆栈视图将不再起作用,因为我有各种相互关联的组件以及 vc 中的移动部件。话虽如此,看来将代码放在 viewDidLayoutSubviews 中实际上可以在向用户显示之前显示元素的正确位置!【参考方案2】:在更新约束后写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()
【讨论】:
【参考方案3】:当你使用 View 时确实出现了,当用户看到 VeiwController 时, 使用 viewDidLoad 代替,你不能使用 viewWillAppear ,因为 View 还没有加载。
使用它:
override func viewDidLoad()
super.viewDidLoad()
你可以试试打电话
self.view.layoutIfNeeded()
【讨论】:
【参考方案4】:当我想以编程方式设置约束时,我通常是这样进行的:
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
【讨论】:
【参考方案5】:您可以为此使用调度队列:
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()
【讨论】:
以上是关于在 viewWillAppear 中设置约束的主要内容,如果未能解决你的问题,请参考以下文章
IOS / Autolayout:在生命周期中为代码中创建的元素设置约束
如何在 Objective C 中的 Xcode 8 中设置约束