layoutSubviews何时被调用?
我有一个自定义视图,在animation过程中不会获取layoutSubview
消息。
我有一个观点,填补了屏幕。 如果我更改导航栏的高度,它将在界面生成器中正确resize的屏幕底部有一个自定义子视图。 layoutSubviews
在创build视图时被调用,但不会再次。 我的子视图是正确的布局。 如果我closures了通话状态栏,那么即使主视图执行了其resize的animation,子视图的layoutSubviews
也不会被调用。
layoutSubviews
在什么情况下实际调用?
我有autoresizesSubviews
设置为NO
为我的自定义视图。 在界面生成器中,我有顶部和底部支柱和垂直箭头集。
我有一个类似的问题,但不满意的答案(或任何我可以在网上find),所以我尝试了在实践中,这就是我得到的:
-
init
不会导致layoutSubviews
被调用(duh) -
addSubview:
使layoutSubviews
在被添加的视图,被添加到的视图(目标视图)和目标的所有子视图上被调用 - 仅当帧的大小参数不同时,
setFrame
智能地在视图上调用layoutSubviews
来设置其框架 - 滚动UIScrollView会导致
layoutSubviews
在scrollView和它的超级视图上被调用 - 旋转设备只调用父视图上的
layoutSubview
(响应的viewControllers主视图) - 调整视图的大小将调用
layoutSubviews
我的结果 – http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-called/
build立在@BadPirate之前的答案上,我进一步尝试了一些,并提出了一些澄清/更正。 我发现layoutSubviews:
只会在layoutSubviews:
情况下被调用:
- 它自己的界限 (不是框架)改变了。
- 其中一个直接子视图的边界改变了。
- 子视图被添加到视图或从视图中删除。
一些相关的细节:
- 只有在新值不同的情况下,边界被认为才会被改变, 包括不同的原点 。 特别注意这就是为什么
layoutSubviews:
在UIScrollView滚动的时候被调用,因为它通过改变边界的原点来执行滚动。 - 改变框架只会改变边界,如果大小已经改变,这是唯一传播到边界属性。
- 尚未处于视图层次结构中的视图边界的更改将导致调用
layoutSubviews:
视图最终被添加到视图层次结构中 。 - 为了完整起见,这些触发器不直接调用layoutSubviews,而是调用
setNeedsLayout
来设置/引发一个标志。 运行循环的每个迭代中,对于视图层次结构中的所有视图,都将检查此标志。 对于发现标志的每个视图,调用layoutSubviews:
并重置该标志。 更高级别的视图将首先被检查/调用。
BadPirate的答案中的一些要点只是部分正确:
-
对于
addSubView
点addSubview
使layoutSubviews在被添加的视图,被添加到的视图(目标视图)和目标的所有子视图上被调用。这取决于视图的(目标视图)自动resize掩码。 如果它具有自动调整掩码ON,则将在每个
addSubview
上调用layoutSubview。 如果它没有自动resize的掩码,那么只有当视图的(目标视图)帧大小发生变化时才会调用layoutSubview。例如:如果以编程方式创build了UIView(默认情况下它没有自动resize的掩码),那么只有在UIView框架没有在每个
addSubview
上更改时才会调用LayoutSubview。正是通过这种技术,应用程序的性能也增加了。
-
对于设备旋转点
旋转设备只调用父视图上的layoutSubview(响应的viewController的主视图)
只有当你的VC在VC层次结构(根目录
window.rootViewController
)时,这才是真的,这是最常见的情况。 在iOS 5中,如果你创build了一个VC,但是它没有被添加到任何其他的VC中,那么这个VC在设备旋转时不会被注意到。 因此,通过调用layoutSubviews,它的视图不会被注意到。
我将解决scheme跟踪到Interface Builder的坚持,弹簧不能在具有模拟屏幕元素(状态栏等)的视图上更改。 由于主要观点的弹簧是closures的,所以这个观点不能改变尺寸,因此在出现呼叫栏时整体向下滚动。
closures模拟function,然后调整视图大小并正确设置弹簧,导致animation发生,并调用我的方法。
在debugging时遇到的一个额外的问题是,当通过菜单切换通话状态时,模拟器退出应用程序。 退出应用程序=没有debugging器。
调用[self.view setNeedsLayout];
在viewController使它调用viewDidLayoutSubviews
在视图中发生以下任何事件时,可能会发生布局更改:
一个。 视图边界矩形的大小发生变化。
湾 发生界面方向更改,通常会触发根视图边界矩形中的更改。
C。 与视图图层相关联的核心animation子图层组发生更改,并且需要布局。
d。 您的应用程序通过调用视图的setNeedsLayout
或layoutIfNeeded
方法来强制执行布局。
即 您的应用程序通过调用视图底层对象的setNeedsLayout
方法来强制布局。
你有没有看过layoutIfNeeded?
文档片段如下。 如果在animation期间显式调用此方法,animation是否工作?
layoutIfNeeded根据需要放置子视图。
- (void)layoutIfNeeded
讨论使用此方法在绘制之前强制子视图的布局。
可用性在iPhone OS 2.0及更高版本中可用。
将OpenGL应用程序从SDK 3迁移到4时,layoutSubviews不再被调用。 经过大量的反复试验后,我终于打开了MainWindow.xib,select了Window对象,在检查器中select了Window Attributes选项卡(最左边)并选中“Visible at launch”。 看起来,在SDK 3中它仍然用于导致layoutSubViews调用,但不是在4中。
6个小时的挫折结束了。
这个难题的另一个部分是窗户必须是关键的:
[window makeKeyAndVisible];
其他子视图不会自动resize。
layoutSubviews
永远不会被调用的另一个比较晦涩但非常重要的情况是:
class View: UIView { override class var layerClass: AnyClass { return Layer.self } class Layer: CALayer { override func layoutSublayers() { // if we don't call super.layoutSublayers() } } override func layoutSubviews() { // this never gets called by the OS! print(#function) } }