首页 > 解决方案 > 旋转设备时更改约束

问题描述

UIView在 Xcode 13 中使用以下布局作为自定义弹出窗口(白色背景是透明的):

在此处输入图像描述

当屏幕方向更改为横向模式时,顶部和底部的约束仍然是 100pts。因此,中间部分(黄色,内部UIView带有UIStackView, UITableView...)非常小,并且控制台中会显示关于顶部(红色)和底部(蓝色)栏的警告:

无法同时满足约束。

我知道这个警告意味着什么。为了修复它,我创建了以下函数......

private let constraintPortrait:CGFloat = 100
private let constraintLandscape:CGFloat = 10

private func fixConstraints() {
    if (UIDevice.current.orientation == .landscapeLeft || UIDevice.current.orientation == .landscapeRight) && UIDevice.current.userInterfaceIdiom == .phone {
        topConstraint.constant = constraintLandscape
        bottomConstraint.constant = constraintLandscape
    } else {
        topConstraint.constant = constraintPortrait
        bottomConstraint.constant = constraintPortrait
    }
}

viewDidLoad...并在和中调用它viewDidLayoutSubviews。这工作得很好,但时不时地仍然会弹出警告,所以我将打印添加到viewDidLoad,... 并注意到警告实际上是在调用约束修复之前打印的。我更名viewDidLayoutSubviewsviewWillLayoutSubviews这里UIViewController的生命周期)和 Abracadabra!,警告消失了。

人们通常建议viewDidLayoutSubviews在设备旋转后想要做一些事情时使用,但几乎没有提及viewWillLayoutSubviews,并且在寻找原因时我找到了这个答案,说不要使用后者来更改约束,因为它可能会导致另一个自动布局通过。

问题:

我应该使用什么来防止冲突(不更改纵向模式的固定约束!)?有没有办法在界面生成器中自动更改顶部和底部约束,而不使用任何代码,并且仅在实际需要时(-> 始终将 100pts 保持在纵向模式,即使是长桌,但立即切换到 10pts在没有足够空间时处于横向模式)?

标签: iosswiftautolayoutnslayoutconstraint

解决方案


viewWillLayoutSubviews是正确的。您在此处执行的任何布局更改,包括约束更改,都将自动与旋转动画相协调。

但是你怎么知道这个调用viewWillLayoutSubviews是由于轮换引起的?实现这个方法:

https://developer.apple.com/documentation/uikit/uicontentcontainer/1621466-viewwilltransition

或者,在 iPhone 上,这种方法:

https://developer.apple.com/documentation/uikit/uicontentcontainer/1621511-willtransition

我喜欢前者,因为它适用于 iPad 和 iPhone。这些在之前被调用viewWillLayoutSubviews,因此您可以设置一个实例属性来向自己发出信号,表明尺寸正在正式更改。您可以通过将边界大小高度与边界大小宽度进行比较来确定发生了什么,并相应地更改约束。


推荐阅读