首先,viewDidLayoutSubviews不是处理oriantion更改的好选项。苹果推荐的方法是viewWillTransitionOnSize。
有关详细信息:
What is the "right" way to handle orientation changes in iOS 8?
第一次运行代码时,堆栈视图显示为垂直分布,第一个视图和第二个视图都有以下约束
第一视图->
Leading = StackView Leading,
Trailing = StackView Trailing,
Top = StackView Top,
height = 80
第二视图->
Leading = StackView Leading ,
Top = FirstView Top,
Trailing = StackView Trailing,
height = 80
当您将设备从纵向旋转到横向时,堆栈视图以水平分布显示,并使以下约束处于活动状态。
FirstView.Width=StackView.Width*1/3
生成的firstview与上一个约束(stackview leading,stackview trailing)冲突。因为现在有两个宽度约束
-
(firstview.leading=stackview leading&firstview.trailing=stackview trailing)=(firstview width==stackview.width)
-
FirstView.Width=StackView.Width*1/3
为什么stackview不自动删除冲突约束之一?
-->因为这两个约束都具有高优先级(1000)。如果我们将firstviewwidth更改为较低的(999),并删除secondviewwidth约束,则解决方案将起作用
尝试用以下代码替换您的代码
import UIKit
class ViewController: UIViewController {
enum DisplayMode {
case regular
case compact
}
private let stackView = UIStackView(frame: .zero)
private let firstView = UIView(frame: .zero)
private let secondView = UIView(frame: .zero)
private var firstViewWidth: NSLayoutConstraint?
private var secondViewWidth: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: view.topAnchor),
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
firstView.backgroundColor = .red
stackView.addArrangedSubview(firstView)
firstView.heightAnchor.constraint(equalToConstant: 80).isActive = true
firstViewWidth = firstView.widthAnchor.constraint(equalTo: stackView.widthAnchor, multiplier: 1/3)
firstViewWidth?.priority = UILayoutPriority(rawValue: 999)
firstViewWidth?.isActive = true
secondView.backgroundColor = .black
stackView.addArrangedSubview(secondView)
secondView.heightAnchor.constraint(equalToConstant: 80).isActive = true
if self.view.bounds.width < 400 {
self.switchMode(.compact)
} else {
self.switchMode(.regular)
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { (context) in
}) { (context) in
if self.view.bounds.width < 400 {
self.switchMode(.compact)
} else {
self.switchMode(.regular)
}
}
}
}
private extension ViewController {
func switchMode(_ mode: DisplayMode) {
switch mode {
case .regular:
stackView.axis = .horizontal
firstViewWidth?.isActive = true
case .compact:
stackView.axis = .vertical
firstViewWidth?.isActive = false
}
}
}