在纵向模式下,我从视图控制器的顶部到底部有四个视图(参见图像)。
然后我想在设备转换为横向时更改视图相对于彼此的位置(参见图2)。
我希望视图4与视图2和3一起移动,并且它们都位于视图1下方。
一些布局条件:
实现不同布局的最佳方法是什么?
最优雅的解决方案是在视图控制器代码中引用约束并在viewWillTransition中激活和停用它们吗?或者是否有一种方法可以使用各种特性来实现这一点(我可以想象水平居中的视图2,3和4将难以实现,以及在横向模式下为视图4添加新约束)? / p>
答案 0 :(得分:19)
我们曾经设置了不同的约束集,并根据方向变化激活/停用它们。但是现在可以使用大小类和“因性状而异”。
例如,我从一个简单的视图开始,选择一个紧凑的宽度大小类,然后选择“Vary for traits”:
然后我添加适当的约束并点击“完成变化”:
然后我选择“常规宽度尺寸类”并重复该过程(“变化为特征”,添加约束,点击“完成变化”:
然后,您将得到一个场景,该场景将对紧凑宽度大小类和常规宽度大小类具有完全不同的约束集。即当我运行应用程序时,如果设备旋转,则会激活新约束:
有关更多信息,请参阅有关自适应布局的WWDC 2016视频:
答案 1 :(得分:1)
我使用约束数组并根据方向激活/停用。
var p = [NSLayoutConstraint]()
var l = [NSLayoutConstraint]()
var initialOrientation = true
var isInPortrait = false
override func viewDidLoad() {
super.viewDidLoad()
// add any subviews here
view.turnOffAutoResizing()
// add constraints here....
// common constraints you can set their isActive = true
// otherwise, add in to portrait(p) and landscape(l) arrays
}
override func viewWillLayoutSubviews() {
super.viewDidLayoutSubviews()
if initialOrientation {
initialOrientation = false
if view.frame.width > view.frame.height {
isInPortrait = false
} else {
isInPortrait = true
}
view.setOrientation(p, l)
} else {
if view.orientationHasChanged(&isInPortrait) {
view.setOrientation(p, l)
}
}
}
extension UIView {
public func turnOffAutoResizing() {
self.translatesAutoresizingMaskIntoConstraints = false
for view in self.subviews as [UIView] {
view.translatesAutoresizingMaskIntoConstraints = false
}
}
public func orientationHasChanged(_ isInPortrait:inout Bool) -> Bool {
if self.frame.width > self.frame.height {
if isInPortrait {
isInPortrait = false
return true
}
} else {
if !isInPortrait {
isInPortrait = true
return true
}
}
return false
}
public func setOrientation(_ p:[NSLayoutConstraint], _ l:[NSLayoutConstraint]) {
NSLayoutConstraint.deactivate(l)
NSLayoutConstraint.deactivate(p)
if self.bounds.width > self.bounds.height {
NSLayoutConstraint.activate(l)
} else {
NSLayoutConstraint.activate(p)
}
}
}
我需要区分肖像或风景需要使用大小类以外的东西,因为我的应用是通用的,iPad(除非使用拆分或滑出视图)总是正常尺寸。此外,您可以使用viewWillTransistion(toSize:)
或viewDidLoadSubviews()
而不是' viewWillLoadSubviews()` - 但始终进行测试,因为这些可能会在方向更改时执行多次!