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的答案中的一些要点只是部分正确:

  1. 对于addSubView

    addSubview使layoutSubviews在被添加的视图,被添加到的视图(目标视图)和目标的所有子视图上被调用。

    这取决于视图的(目标视图)自动resize掩码。 如果它具有自动调整掩码ON,则将在每个addSubview上调用layoutSubview。 如果它没有自动resize的掩码,那么只有当视图的(目标视图)帧大小发生变化时才会调用layoutSubview。

    例如:如果以编程方式创build了UIView(默认情况下它没有自动resize的掩码),那么只有在UIView框架没有在每个addSubview上更改时才会调用LayoutSubview。

    正是通过这种技术,应用程序的性能也增加了。

  2. 对于设备旋转点

    旋转设备只调用父视图上的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

https://developer.apple.com/library/prerelease/tvos/documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/CreatingViews/CreatingViews.html#//apple_ref/doc/uid/TP40009503-CH5-SW1

在视图中发生以下任何事件时,可能会发生布局更改:

一个。 视图边界矩形的大小发生变化。
湾 发生界面方向更改,通常会触发根视图边界矩形中的更改。
C。 与视图图层相关联的核心animation子图层组发生更改,并且需要布局。
d。 您的应用程序通过调用视图的setNeedsLayoutlayoutIfNeeded方法来强制执行布局。
即 您的应用程序通过调用视图底层对象的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) } }