是什么导致容器视图保持其子视图的框架与其边界匹配?

时间:2013-06-30 02:22:23

标签: ios objective-c uikit

我正在努力更好地了解容器视图在故事板中的工作原理。行为似乎是容器视图将强制其子视图调整大小以填充容器。

storyboard relationships

我看不到解释它的约束,也没有提到它是什么类。这似乎是一些故事板的魔力。

constraints

我假设容器视图必须是UIView的子类,我会猜测并假设它被称为UIContainerView,但搜索文档只会产生两个结果。

search results

那它是如何运作的?

2 个答案:

答案 0 :(得分:27)

故事板编辑器(Interface Builder)在编辑期间将嵌入视图的frame设置为容器视图的bounds。因此,当故事板被写入文件时,视图的序列化大小是相同的。无论故事板是否启用了自动布局,都会发生这种情况。

故事板中每个视图控制器的顶级视图也将其自动调整遮罩设置为UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight,无论故事板是否启用了自动布局。

如果启用了自动布局,则每个顶级视图的translatesAutoresizingMaskToConstraints都设置为YES。这与那些顶级视图的所有后代不同。所有后代都将translatesAutoresizingMaskToConstraints设置为NO

嵌入关系表示为类UIStoryboardEmbedSegue的segue。 (这是私有类,不属于公共API。)

UIStoryboardEmbedSegue收到perform消息时,它会加载目标视图控制器的视图并将其添加为容器视图的子视图。然后,它将嵌入视图的autoresizingMask设置为UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight。这是多余的,因为Interface Builder已经在故事板中设置了它。

然后-[UIStoryboardEmbedSegue perform]检查嵌入视图的translatesAutoresizingMaskToConstraints。这也是多余的,因为Interface Builder将其设置为YES

如果嵌入视图的translatesAutoresizingMaskToConstraintsYES,则perform会将嵌入视图的frame设置为容器视图的bounds。再次,冗余。

如果嵌入视图的translatesAutoresizingMaskToConstraintsNO,则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>

这就是“导致容器视图保持其子视图的框架与其边界匹配”的原因。

我通过查看.storyboard文件(令人惊讶的可读XML)以及查看Hopper中的-[UIStoryboardEmbedSegue perform]来解决这个问题。

至于他们为什么要进行冗余检查,我可以想到几个可能的原因:

  1. IB(可能在预发布版本中)并不总是像现在一样设置视图属性,因此在加载旧故事板时代码不会多余。

  2. Apple拥有的内部工具可以生成与IB不同的故事板。

  3. 代码用于向前兼容IB的未来版本,允许顶级故事板视图具有不同的属性。

答案 1 :(得分:0)

设置测试项目并单步执行代码可以让您清楚地了解如何实现它。容器视图本身是一个简单的UIView。作为控制器loadView进程的一部分,使用故事板中的约束设置创建容器视图。然后执行嵌入式控制器segue。这将创建子视图控制器,该视图将其视图添加为容器视图的子视图,并设置适当的布局约束,以便子视图填充容器。多数民众赞成真的。