284

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

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

什么情况下layoutSubviews实际调用?

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


难题的另一部分是必须将窗口设为关键:

[window makeKeyAndVisible];

否则子视图不会自动调整大小。

4

8 回答 8

518

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

  • init不会导致layoutSubviews被调用(duh)
  • addSubview:导致 layoutSubviews在添加的视图、添加到的视图(目标视图)以及目标的所有子视图上调用
  • 仅当框架的大小参数不同时,视图才setFrame 智能地调用layoutSubviews已设置其框架的视图
  • 滚动 UIScrollView 会导致layoutSubviews在 scrollView 及其父视图上被调用
  • 旋转设备仅调用 layoutSubview父视图(响应的 viewControllers 主视图)
  • 调整视图大小将调用layoutSubviews其父视图(重要提示: 如果确定其大小的内容发生变化,则具有内在内容大小的视图将重新调整大小;例如,更新 UILabel 上的文本将导致更新内在内容大小,因此调用layoutSubviews它的superview

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

于 2011-03-16T18:42:58.673 回答
111

在@BadPirate 之前的回答的基础上,我做了一些进一步的实验,并提出了一些澄清/更正。我发现layoutSubviews:当且仅当:

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

一些相关细节:

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

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 or layoutIfNeeded 方法来强制进行布局。
e. setNeedsLayout 您的应用程序通过调用视图底层对象的方法来强制布局 。

于 2015-09-10T06:14:36.963 回答
13

BadPirate 的回答中的一些观点只是部分正确:

  1. addSubView

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

    它取决于视图的(目标视图)自动调整大小掩码。如果它启用了自动调整掩码,layoutSubview 将在每个addSubview. 如果它没有自动调整大小掩码,则仅当视图的(目标视图)帧大小更改时才会调用 layoutSubview。

    示例:如果您以编程方式创建 UIView(默认情况下它没有自动调整大小掩码),则仅当 UIView 框架更改时才会调用 LayoutSubview addSubview

    正是通过这种技术,应用程序的性能也得到了提高。

  2. 对于设备旋转点

    旋转设备仅调用父视图(响应视图控制器的主视图)上的 layoutSubview

    仅当您的 VC 位于 VC 层次结构中时(根位于window.rootViewController),这才是正确的,这是最常见的情况。在 iOS 5 中,如果你创建了一个 VC,但它没有被添加到任何另一个 VC 中,那么当设备旋转时,这个 VC 不会被注意到。因此,调用 layoutSubviews 不会注意到它的视图。

于 2012-10-29T11:59:14.370 回答
9

我将解决方案追溯到 Interface Builder 坚持认为在打开了模拟屏幕元素(状态栏等)的视图上不能更改弹簧。由于主视图的弹簧已关闭,因此该视图无法更改大小,因此在出现通话栏时会完全向下滚动。

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

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

于 2009-04-09T14:41:40.763 回答
9

调用 [self.view setNeedsLayout]; viewController 使其调用 viewDidLayoutSubviews

于 2014-02-14T20:39:58.470 回答
6

你看过layoutIfNeeded吗?

文档片段如下。如果在动画期间显式调用此方法,动画是否有效?

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

- (void)layoutIfNeeded

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

可用性 适用于 iPhone OS 2.0 及更高版本。

于 2009-04-08T04:12:24.483 回答
2

将 OpenGL 应用程序从 SDK 3 迁移到 4 时,不再调用 layoutSubviews。经过大量试验和错误后,我终于打开了 MainWindow.xib,选择了 Window 对象,在检查器中选择了 Window Attributes 选项卡(最左侧)并选中了“Visible at launch”。似乎在 SDK 3 中它仍然会导致 layoutSubViews 调用,但在 4 中没有。

6小时的挫败感告一段落。

于 2010-06-24T07:13:42.850 回答