什么时候调用layoutSubviews?

Ste*_*ler 259 cocoa-touch bounds ios layoutsubviews autolayout

我有一个自定义视图,layoutSubview在动画期间没有收到消息.

我有一个填充屏幕的视图.如果我更改导航栏的高度,它在屏幕底部有一个自定义子视图,可以在Interface Builder中正确调整大小.layoutSubviews在创建视图时调用,但从不再调用.我的子视图已正确布局.如果我关闭通话中状态栏,layoutSubviews则根本不会调用子视图,即使主视图确实为其调整大小设置了动画.

在什么情况下layoutSubviews实际上被称为?

我已经autoresizesSubviews设置NO为我的自定义视图.在Interface Builder中,我有顶部和底部支柱以及垂直箭头设置.

Bad*_*ate 478

我有一个类似的问题,但对答案(或者我在网上找到的任何答案)都不满意,所以我在实践中尝试过,这就是我得到的:

  • init不会layoutSubviews被称为(duh)
  • addSubview:导致 layoutSubviews在添加的视图,添加到的视图(目标视图)以及目标的所有子视图上调用
  • 视图setFrame 智能电话layoutSubviews上的图,其具有它的帧中设置仅在帧的尺寸参数是不同
  • 滚动UIScrollView导致layoutSubviews在scrollView及其superview上调用
  • 旋转设备只调用 layoutSubview父视图(响应的viewControllers主视图)
  • 调整视图大小将调用layoutSubviews其超级视图

我的结果 - http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-called/

  • @BadPirate:**是**.根据我的实验,如果你调整`view1.1`它会调用`view1`的`layoutSubviews`然后调用`view1.1`的`layoutSubviews`.此调用不会无限期地传播到超级视图,在`view1.1.1`上调用它只会在`view1.1`和`view1.1.1`上调用`layoutSubviews`.只需移动而不改变它的大小就不会在其中任何一个上调用`layoutSubviews`. (7认同)
  • @Robert - 我使用的是initWithFrame ......所以没有. (2认同)
  • 根据我的实验,第二条规则可能不准确:当我将`view1.2`添加到`view1`中时,`view1.2`和`view1`的`layoutSubviews`被调用,而`view1.2`的`layoutSubviews`被调用。 1` 没有被调用。(`view1.1` 和`view1.2` 是`view1` 的子视图)。**也就是说,并不是所有目标视图的子视图都被称为`layoutSubviews`方法**。 (2认同)

Pat*_*pel 84

在@BadPirate之前的回答的基础上,我进行了一些实验,并提出了一些澄清/更正.我发现layoutSubviews:只有在以下情况下才会在视图上调用:

  • 它自己的边界(不是框架)改变了.
  • 其中一个直接子视图的界限发生了变化.
  • 子视图将添加到视图中或从视图中删除.

一些相关细节:

  • 仅当新值不同(包括不同的原点)时,才会将边界视为已更改.请注意,这就是为什么layoutSubviews:每当UIScrollView滚动时调用它,因为它通过更改其边界的原点来执行滚动.
  • 更改框架只会在大小发生变化时更改边界,因为这是传播到bounds属性的唯一内容.
  • 视图层次结构中尚未处于视图边界的更改将导致调用layoutSubviews: 视图最终添加到视图层次结构中.
  • 而且只是为了完整性:这些触发器不直接调用layoutSubviews,而是调用setNeedsLayout,它设置/引发一个标志.对于视图层次结构中的所有视图,运行循环的每次迭代都会检查此标志.对于发现引发标志的每个视图, layoutSubviews:调用它并重置标志.将首先检查/调用层次结构中较高的视图.

  • 不能足够赞成这个答案.它应该是最好的答案.给出的三条规则就是你所需要的.我从来没有遇到过这些规则没有完美描述的layoutSubview行为. (5认同)
  • 我认为当直接子视图的边界更改时不会调用layoutSubviews。我认为layoutSubviews 的调用只是您测试的副作用。在某些情况下,当子视图边界更改时,layoutSubviews 将不会被调用。请检查 frogcjn 的答案,因为他的答案是基于 Apple 的文档而不仅仅是实验。 (2认同)

fro*_*cjn 19

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

只要视图中发生以下任何事件,就会发生布局更改:

一个.视图边界矩形的大小会发生变化.
湾 发生界面方向更改,这通常会触发根视图边界矩形的更改.
C.与视图图层关联的核心动画子图层集会更改并需要布局.
d.您的应用程序通过调用 视图的方法setNeedsLayout 或  layoutIfNeeded方法来强制进行布局  .
即 您的应用程序通过调用setNeedsLayout 视图的基础图层对象的方法来强制布局  .


小智 11

BadPirate的答案中的一些要点只是部分正确:

  1. 为了addSubView

    addSubview 导致layoutSubviews在要添加的视图,要添加到的视图(目标视图)以及目标的所有子视图上被调用.

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

    示例:如果您以编程方式创建了UIView(默认情况下它没有自动调整大小),则仅当UIView帧不在每次更改时才会调用LayoutSubview addSubview.

    通过这种技术,应用程序的性能也会提高.

  2. 用于设备旋转点

    旋转设备只调用父视图上的layoutSubview(响应的viewController的主视图)

    只有当您的VC位于VC层次结构(root at window.rootViewController)中时才会出现这种情况,这是最常见的情况.在iOS 5中,如果您创建了一个VC,但它没有被添加到任何其他VC中,那么当设备旋转时,此VC就不会被注意到.因此,调用layoutSubviews不会注意到它的视图.


Ste*_*ler 8

我将解决方案跟踪到Interface Builder的坚持,即在打开模拟屏幕元素的视图(状态栏等)上无法更改弹簧.由于弹簧在主视图中关闭,因此该视图无法改变大小,因此当呼叫栏出现时,该视图完全向下滚动.

关闭模拟功能,然后调整视图大小并正确设置弹簧会导致动画发生并调用我的方法.

调试时的另一个问题是,当通过菜单切换通话中状态时,模拟器退出应用程序.退出app =没有调试器.


小智 8

[self.view setNeedsLayout]; 在viewController中调用 使它调用viewDidLayoutSubviews


Wil*_*hin 5

您是否看过layoutIfNeeded?

文档片段如下。如果在动画过程中显式调用此方法,动画是否起作用?

layoutIfNeeded如果需要,布置子视图。

- (void)layoutIfNeeded
Run Code Online (Sandbox Code Playgroud)

讨论使用此方法可以在绘制之前强制子视图的布局。

可用性在iPhone OS 2.0和更高版本中可用。