如何在显示旋转时以编程方式更改布局约束
Posted
技术标签:
【中文标题】如何在显示旋转时以编程方式更改布局约束【英文标题】:How to change layout constraints programmatically on display rotation 【发布时间】:2014-12-14 20:37:26 【问题描述】:对于一个应用程序(ios 7 兼容),我需要能够在横向和纵向模式下进行完全不同的布局。我看到以编程方式设置约束并在旋转时更改它们的唯一方法。所以我使用 IB 设置我的界面,然后以编程方式设置约束。
我在某处看到了首先删除所有约束,然后创建并添加新约束,然后为父视图上的约束设置更新标志的方法。我希望元素只是屏幕的全宽,一个在另一个下方:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
self.landscapeConstraints = [NSMutableArray new];
self.portraitConstraints = self.view.constraints;
//creation of the viewsDictionary
[self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[segmentedControl]-|" options:0 metrics:nil views:viewsDictionary]];
[self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[fullText]-|" options:0 metrics:nil views:viewsDictionary]];
[self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[bubbleTitle]-|" options:0 metrics:nil views:viewsDictionary]];
[self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[bubble]-|" options:0 metrics:nil views:viewsDictionary]];
[self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[chartView]-|" options:0 metrics:nil views:viewsDictionary]];
[self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(20)-[segmentedControl]-[fullText]-[bubbleTitle]-[bubble]-[chartView]|" options:0 metrics:nil views:viewsDictionary]];
[self.view removeConstraints:self.portraitConstraints];
[self.view addConstraints:self.landscapeConstraints];
[self.view setNeedsUpdateConstraints];
我的问题:这种方式是否完整且正确?
我来这个问题,因为旋转后元素太大了。看起来超级视图的大小在旋转后不正确。因此所有元素都太大了,似乎最大的元素(长文本标签)给出了宽度,这比屏幕大得多。如果我在约束中设置了一个具有大小的元素(例如 [segmentedControl(==500)],那么这个元素的大小是可以的,并且所有其他元素也具有该大小。
命令
NSLog(@"%@", [self.view performSelector:@selector(_autolayoutTrace)]);
所有元素都给了我这样的东西:
*UIView:0x7f9a38f36510- AMBIGUOUS LAYOUT for UIView:0x7f9a38f36510.minXid: 9, UIView:0x7f9a38f36510.minYid: 12, UIView:0x7f9a38f36510.Widthid: 15, UIView:0x7f9a38f36510.Heightid: 17
谁能提示我哪里做错了?我正在为此工作几个小时......
编辑
我真的不明白:似乎我删除所有约束后的解决方案是通过这样的约束来定义超级视图的大小:
NSDictionary *viewsDictionary = @ @"view":self.view;
[self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[view(360)]" options:0 metrics:nil views:viewsDictionary]];
[self.landscapeConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[view(650)]" options:0 metrics:nil views:viewsDictionary]];
否则所有视图都会崩溃,因为超级视图的大小似乎为零。即使有这些额外的限制,视图仍然位于太左(大约 20 像素)!
谁能给我解释一下?我真的需要使用当前窗口大小手动生成该约束吗?我希望包含视图(即主窗口)具有全屏的大小。
【问题讨论】:
【参考方案1】:您可以像以前一样设置布局约束,但您也可以使用 IBOutlet 引用它们并以编程方式更改它们(然后调用 layoutIfNeeded
)。不看布局就很难分析你的代码,但你的日志显示约束不够精确(模棱两可)。要知道哪个视图是哪个视图,您也可以单独记录视图并获取每个视图的缺失约束。然后一一设置约束,使其不再模棱两可。
在您的声明中:
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *leftMarginViewXYZ;
然后在 Interface Builder 中右键单击约束并绘制对 ViewController 的引用。释放按钮时,您选择正确的约束。
然后你可以在你的代码中改变约束
self.leftMarginViewXYZ.constant = 123;
[self.view layoutIfNeeded];
【讨论】:
那么我如何访问约束并使用 IBOutlet 修改它们?以上是关于如何在显示旋转时以编程方式更改布局约束的主要内容,如果未能解决你的问题,请参考以下文章
旋转设备时以编程方式将视图添加到父 LinearLayout 会重复最后一个条目