我有一个自定义视图在动画期间没有收到 layoutSubview
消息。
我有一个充满屏幕的视图。如果我更改导航栏的高度,它在屏幕底部有一个自定义子视图,可以在 Interface Builder 中正确调整大小。 layoutSubviews
在创建视图时调用,但不再调用。我的子视图布局正确。如果我关闭通话状态栏,则根本不会调用子视图的 layoutSubviews
,即使主视图确实为其调整大小设置了动画。
在什么情况下实际调用了 layoutSubviews
?
我将自定义视图的 autoresizesSubviews
设置为 NO
。在 Interface Builder 中,我设置了顶部和底部支柱以及垂直箭头。
难题的另一部分是必须将窗口设为关键:
[window makeKeyAndVisible];
否则子视图不会自动调整大小。
我有一个类似的问题,但对答案(或我能在网上找到的任何答案)不满意,所以我在实践中尝试过,这就是我得到的:
init 不会导致 layoutSubviews 被调用(duh)
addSubview:导致 layoutSubviews 在被添加的视图、被添加到的视图(目标视图)以及目标的所有子视图上调用
视图 setFrame 仅在框架的大小参数不同时智能地调用已设置其框架的视图上的 layoutSubviews
滚动 UIScrollView 会导致在 scrollView 及其父视图上调用 layoutSubviews
旋转设备仅在父视图(响应的 viewControllers 主视图)上调用 layoutSubview
调整视图的大小将在其父视图上调用 layoutSubviews (重要:如果确定其大小的内容发生更改,则具有内在内容大小的视图将重新调整大小;例如,更新 UILabel 上的文本将导致更新内在内容大小和因此在其父视图上调用 layoutSubviews)
我的结果 - http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-called/
在@BadPirate 之前的回答的基础上,我做了一些进一步的实验,并提出了一些澄清/更正。我发现当且仅当以下情况下才会在视图上调用 layoutSubviews:
:
它自己的界限(不是框架)发生了变化。
它的直接子视图之一的边界发生了变化。
子视图被添加到视图中或从视图中删除。
一些相关细节:
仅当新值不同(包括不同的原点)时,才认为边界已更改。请特别注意,这就是为什么 layoutSubviews: 在 UIScrollView 滚动时调用的原因,因为它通过更改其边界的原点来执行滚动。
更改框架只会在大小发生更改时更改边界,因为这是传播到边界属性的唯一内容。
尚未在视图层次结构中的视图边界的更改将导致对 layoutSubviews 的调用:当视图最终添加到视图层次结构中时。
并且只是为了完整性:这些触发器不直接调用 layoutSubviews,而是调用 setNeedsLayout,它设置/引发一个标志。运行循环的每次迭代,对于视图层次结构中的所有视图,都会检查此标志。对于发现标志的每个视图,都会调用 layoutSubviews: 并重置标志。层次较高的视图将首先被检查/调用。
每当视图中发生以下任何事件时,都可能发生布局更改:视图边界矩形的大小发生变化。湾。发生界面方向更改,这通常会触发根视图的边界矩形的更改。 C。与视图层关联的一组核心动画子层发生变化并需要布局。 d。您的应用程序通过调用视图的 setNeedsLayout 或 layoutIfNeeded 方法来强制进行布局。 e.您的应用程序通过调用视图底层对象的 setNeedsLayout 方法来强制布局。
https://i.stack.imgur.com/4LSv0.png
BadPirate's answer 中的一些观点只是部分正确:
对于 addSubView 点 addSubview 导致 layoutSubviews 在被添加的视图、它被添加到的视图(目标视图)以及目标的所有子视图上被调用。它取决于视图的(目标视图)自动调整大小掩码。如果它启用了自动调整掩码,layoutSubview 将在每个 addSubview 上调用。如果它没有自动调整大小掩码,则仅当视图的(目标视图)帧大小更改时才会调用 layoutSubview。示例:如果您以编程方式创建了 UIView(默认情况下它没有自动调整大小掩码),则仅当 UIView 框架更改而不是在每个 addSubview 上时才会调用 LayoutSubview。正是通过这种技术,应用程序的性能也得到了提高。对于设备旋转点 旋转设备仅调用父视图(响应 viewController 的主视图)上的 layoutSubview 仅当您的 VC 位于 VC 层次结构中(window.rootViewController 的根目录)时才会如此,这是最常见的情况。在 iOS 5 中,如果你创建了一个 VC,但它没有被添加到任何另一个 VC 中,那么当设备旋转时,这个 VC 不会被注意到。因此,调用 layoutSubviews 不会注意到它的视图。
我将解决方案追溯到 Interface Builder 坚持认为在打开了模拟屏幕元素(状态栏等)的视图上不能更改弹簧。由于主视图的弹簧已关闭,因此该视图无法更改大小,因此在出现通话栏时会完全向下滚动。
关闭模拟功能,然后调整视图大小并正确设置弹簧会导致动画发生并调用我的方法。
调试中的一个额外问题是,当通过菜单切换通话状态时,模拟器会退出应用程序。退出应用程序 = 没有调试器。
在 viewController 中调用 [self.view setNeedsLayout];
使其调用 viewDidLayoutSubviews
你看过layoutIfNeeded吗?
文档片段如下。如果在动画期间显式调用此方法,动画是否有效?
layoutIfNeeded 如果需要,布局子视图。
- (void)layoutIfNeeded
讨论 使用此方法在绘制之前强制子视图的布局。
可用性 适用于 iPhone OS 2.0 及更高版本。
将 OpenGL 应用程序从 SDK 3 迁移到 4 时,不再调用 layoutSubviews。经过大量试验和错误后,我终于打开了 MainWindow.xib,选择了 Window 对象,在检查器中选择了 Window Attributes 选项卡(最左侧)并选中了“Visible at launch”。似乎在 SDK 3 中它仍然会导致 layoutSubViews 调用,但在 4 中没有。
6小时的挫败感告一段落。
layoutSubviews
。initWithFrame:
会导致layoutSubviews
被调用吗?view1.1
的大小,它会调用view1
的layoutSubviews
,然后调用view1.1
的layoutSubviews
。此调用不会无限期地传播到超级视图,在view1.1.1
上调用它只会在view1.1
和view1.1.1
上调用layoutSubviews
。只是移动而不改变它的大小不会对它们中的任何一个调用layoutSubviews
。view1.2
添加到view1
时,会调用view1.2
和view1
的layoutSubviews
,但不会调用view1.1
的layoutSubviews
。 (view1.1
和view1.2
是view1
的子视图)。 也就是说,并不是目标视图的所有子视图都调用了layoutSubviews
方法。