我试图更好地理解容器视图在故事板中的工作方式。行为似乎是容器视图将强制其子视图调整大小以填充容器。
我没有看到可以解释它的限制,也没有提到它是什么类。这似乎是一些故事板魔术。
我假设容器视图必须是 的子类UIView
,并且我会大胆猜测并假设它是被调用的UIContainerView
,但是通过文档搜索只会产生两个结果。
那么它是怎样工作的?
我试图更好地理解容器视图在故事板中的工作方式。行为似乎是容器视图将强制其子视图调整大小以填充容器。
我没有看到可以解释它的限制,也没有提到它是什么类。这似乎是一些故事板魔术。
我假设容器视图必须是 的子类UIView
,并且我会大胆猜测并假设它是被调用的UIContainerView
,但是通过文档搜索只会产生两个结果。
那么它是怎样工作的?
故事板编辑器(界面生成器)在编辑期间将嵌入视图frame
设置为容器视图bounds
。因此,当故事板被写入文件时,视图的序列化大小是相同的。无论故事板是否启用了自动布局,都会发生这种情况。
故事板中每个视图控制器的顶级视图也将其自动调整掩码设置为UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
,同样无论故事板是否启用了自动布局。
如果启用了自动布局,则每个顶级视图都translatesAutoresizingMaskToConstraints
设置为YES
. 这与那些顶级视图的所有后代不同。所有的后代都translatesAutoresizingMaskToConstraints
设置为NO
。
嵌入关系表示为 class 的 segue UIStoryboardEmbedSegue
。(这是一个私有类,不是公共 API 的一部分。)
当UIStoryboardEmbedSegue
收到perform
消息时,它会加载目标视图控制器的视图并将其添加为容器视图的子视图。然后它将嵌入视图的设置autoresizingMask
为UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
. 这是多余的,因为 Interface Builder 已经在故事板中设置了这种方式。
然后-[UIStoryboardEmbedSegue perform]
检查嵌入视图的translatesAutoresizingMaskToConstraints
. 这也是多余的,因为 Interface Builder 将其设置为YES
.
如果嵌入视图translatesAutoresizingMaskToConstraints
是YES
,perform
则将嵌入视图设置frame
为容器视图bounds
。再次,多余的。
如果嵌入视图translatesAutoresizingMaskToConstraints
是NO
,则perform
添加约束H:|[childView]|
和V:|[childView]|
,从而强制嵌入视图填充容器视图。(是的,它实际上使用了可视化格式语言。)不应到达此分支。
当视图translatesAutoresizingMaskToConstraints
设置为 时YES
,自动布局会自动添加类型约束,NSAutoresizingMaskLayoutConstraint
并在您更改视图的frame
. 例如,窗口的根视图使用自动调整大小约束来填充窗口:
<NSAutoresizingMaskLayoutConstraint:0x7555d00 h=-&- v=-&- UIView:0x7671780.midX == UIWindow:0x7551010.midX>,
<NSAutoresizingMaskLayoutConstraint:0x7555de0 h=-&- v=-&- UIView:0x7671780.width == UIWindow:0x7551010.width>,
<NSAutoresizingMaskLayoutConstraint:0x7555eb0 h=-&- v=-&- UIView:0x7671780.midY == UIWindow:0x7551010.midY + 10>,
<NSAutoresizingMaskLayoutConstraint:0x7555ef0 h=-&- v=-&- UIView:0x7671780.height == UIWindow:0x7551010.height - 20>
这就是“导致 Container View 保持其子视图的框架与其边界匹配”的原因。
我通过查看.storyboard
文件(它的可读性令人惊讶的 XML)和-[UIStoryboardEmbedSegue perform]
在Hopper中查看了这一点。
至于为什么他们有多余的检查,我可以想到几个可能的原因:
IB(可能在预发布版本中)并不总是像现在这样设置视图属性,因此在加载旧故事板时代码不是多余的。
Apple 的内部工具生成故事板的方式与 IB 不同。
该代码用于与 IB 的未来版本向前兼容,允许顶级故事板视图具有不同的属性。
设置一个测试项目并逐步执行代码可以让您相当清楚地了解它是如何实现的。容器视图本身是一个普通的 UIView。作为控制器 loadView 过程的一部分,容器视图是使用情节提要中的约束设置创建的。然后执行嵌入式控制器segue。这将创建子视图控制器,该控制器将其视图添加为容器视图的子视图,并设置适当的布局约束,以便子视图填充容器。真的就是这样。