在Apple引入自动布局系统之前,iOS应用一直使用自动缩放掩码管理视图布局,视图只具有相对于父视图的自动缩放掩码,无法设置与兄弟视图之间的布局关系。
默认情况下,视图会将自动缩放掩码转换为对应的约束,这类约束经常会与手动添加的约束产生冲突,下面就演示这类冲突。
在viewDidLoad中,注释掉禁用转换自动缩放掩码的代码:
// 设置UIImageView对象的内容缩放模式
iv.contentMode = UIViewContentModeScaleAspectFit;
// 告诉自动布局系统不要将自动缩放掩码转换为约束
// iv.translatesAutoresizingMaskIntoConstraints = NO;
// 将UIImageView对象添加到view上
[self.view addSubview:iv];
现在UIImageView对象会将自动缩放掩码转换为约束。构建并运行应用,然后进入详细界面。这时控制台会输出布局问题和解决建议。
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't
want. Try this: (1) look at each constraint and try to figure out which you don't
expect; (2) find the code that added the unwanted constraint or constraints and
fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property
translatesAutoresizingMaskIntoConstraints)
(
“”,
“<NSLayoutConstraint:0x9153ee0
H:|-(20)-[UILabel:0x9149f00] (Names: '|':UIControl:0x91496e0 )>”,
“<NSLayoutConstraint:0x9153fa0
UILabel:0x9149970.leading == UILabel:0x9149f00.leading>”,
“<NSLayoutConstraint:0x91540c0
UILabel:0x914a1e0.leading == UILabel:0x9149970.leading>”,
“<NSLayoutConstraint:0x9154420
H:[UITextField:0x914fe20]-(20)-|
(Names: '|':UIControl:0x91496e0 )>”,
“<NSLayoutConstraint:0x9154450
H:[UILabel:0x914a1e0]-(12)-[UITextField:0x914fe20]>”,
“<NSLayoutConstraint:0x912f5a0 (Names: '|':UIControl:0x91496e0 )>”,
H:|-(NSSpace(20))-[UIImageView:0x91524d0
“<NSLayoutConstraint:0x91452a0 (Names: '|':UIControl:0x91496e0 )>”,
H:[UIImageView:0x91524d0]-(NSSpace(20))-|
“<NSAutoresizingMaskLayoutConstraint:0x905f130
h=--& v=--& UIImageView:0x91524d0.midX ==>”
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x914a2e0 H:[UILabel:0x914a1e0(42)]>
第15章介绍过,以上输出表明多个约束之间发生了冲突,Xcode无法同时满足所有约束。其中,与问题相关的所有约束都会以固定格式依次列举出来,例如,
<NSLayoutConstraint:0x9153fa0
UILabel:0x9149970.leading == UILabel:0x9149f00.leading>
以上格式首先是约束对象的类名和内存地址,然后是约束的作用,在本例中,位于0x9153fa0的约束限定0x9153fa0和0x9149970两个UILabel对象左对齐。
可以注意到,按照以上格式,除最后一个约束外,其余约束的类名都是NSLayoutConstraint。最后一个约束是由UIImageView对象的自动缩放掩码转换而来的,所以类名是NSAutoresizingMaskLayoutConstraint。
最后是Xcode所忽略的约束。可以看到,Xcode忽略的是之前手动为UILabel对象添加的宽度约束,而不是NSAutoresizingMaskLayoutConstraint对象,所以导致界面布局与期望不同。
现在读者可以理解设置translatesAutoresizingMaskIntoConstraints属性为NO的原因了,其作用就是避免自动布局系统生成与其他约束产生冲突的NSAutoresizingMask- LayoutConstraint对象。
最后请读者恢复viewDidLoad中的代码:
// 设置UIImageView对象的内容缩放模式
iv.contentMode = UIViewContentModeScaleAspectFit;
// 告诉自动布局系统不要将自动缩放掩码转换为约束
iv.translatesAutoresizingMaskIntoConstraints = NO;
// 将UIImageView对象添加到view上
[self.view addSubview:iv];