XCode:如何在横向和纵向模式之间更改视图布局
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42318186/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
XCode: How to change layout of views between landscape and portrait mode
提问by Fred White
In portrait mode I have four views on top of one another from the top to the bottom of the view controller (see image).
在纵向模式下,我有四个视图,从视图控制器的顶部到底部相互叠加(见图)。
I then want to change the position of the views relative to one another when the device transitions to landscape (see image two).
然后,当设备转换为横向时,我想更改视图相对于彼此的位置(见图二)。
I want view 4 to move alongside views 2 and 3 and them all the sit below view 1.
我希望视图 4 与视图 2 和 3 一起移动,并且它们都位于视图 1 的下方。
Some of the layout conditions:
一些布局条件:
- view 1 is attached to the top of the view controller in both landscape and portrait.
- view 4 is attached to the left, right and bottom margins of the view controller in portrait mode.
- Views 2, 3 & 4 are centered horizontally within the portrait view.
- 视图 1 附加到横向和纵向视图控制器的顶部。
- 在纵向模式下,视图 4 附加到视图控制器的左侧、右侧和底部边距。
- 视图 2、3 和 4 在纵向视图中水平居中。
What is the best method to achieve the different layouts?
实现不同布局的最佳方法是什么?
Would the most elegant solution be to make a reference to the constraints in the view controllers code and activate and deactivate them in viewWillTransition? Or is there a way to use vary for traits to achieve this (I can imagine views 2, 3 & 4 being centered horizontally would make this hard to achieve, as well as adding the new constraints for view 4 in landscape mode)?
最优雅的解决方案是在视图控制器代码中引用约束并在 viewWillTransition 中激活和停用它们吗?或者有没有办法使用不同的特征来实现这一点(我可以想象水平居中的视图 2、3 和 4 会使这难以实现,以及在横向模式下为视图 4 添加新的约束)?
回答by Rob
We used to set up different sets of constraints and activate/deactivate them based upon orientation change. But nowadays can use size classes and "vary for traits".
我们过去常常设置不同的约束集,并根据方向的变化激活/停用它们。但是现在可以使用大小类并“因特征而异”。
For example, I start with a simple view and choose a compact width size class and then choose "Vary for traits":
例如,我从一个简单的视图开始,选择一个紧凑的宽度尺寸类,然后选择“为特征而变化”:
I then add the appropriate constraints and click on "Done varying":
然后我添加适当的约束并单击“完成变化”:
I then choose a "regular width size class" and repeat the process ("Vary for traits", add the constraints, click on "Done varying":
然后我选择一个“常规宽度尺寸类”并重复这个过程(“根据特征变化”,添加约束,点击“完成变化”:
You then end up with a scene that will have a completely different set of constraints active for compact width size classes and regular width size classes. I.e. when I run the app, if the device rotates, the new constraints are activated:
然后,您最终会得到一个场景,该场景将具有一组完全不同的约束,适用于紧凑宽度尺寸类别和常规宽度尺寸类别。即当我运行应用程序时,如果设备旋转,新的约束被激活:
For more information, see WWDC 2016 videos on adaptive layouts:
有关更多信息,请参阅有关自适应布局的 WWDC 2016 视频:
回答by dfd
I use arrays of constraints and activate/deactivate according to orientation.
我使用约束数组并根据方向激活/停用。
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)
}
}
}
My needs to distinguish portrait or landscape requireusing something other than size classes, as my app is universal and iPad (unless using split or slide out view) is alwaysnormal size. Also, you may get use viewWillTransistion(toSize:)
or viewDidLoadSubviews()
instead of 'viewWillLoadSubviews()` - but always test, as these may be executed more than once on an orientation change!
我需要区分纵向或横向需要使用尺寸类别以外的其他东西,因为我的应用程序是通用的,而 iPad(除非使用拆分或滑出视图)始终是正常尺寸。此外,您可能会使用viewWillTransistion(toSize:)
或viewDidLoadSubviews()
代替“viewWillLoadSubviews()” - 但始终进行测试,因为这些可能会在方向更改时执行多次!