什么时候调用layoutSubviews?

时间:2009-04-08 03:05:13

标签: ios cocoa-touch autolayout bounds layoutsubviews

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

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

在什么情况下实际调用autoresizesSubviews

我的自定义视图设置为NO [window makeKeyAndVisible]; 。在Interface Builder中,我有顶部和底部支柱以及垂直箭头设置。


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

{{1}}

其他子视图不会自动调整大小。

9 个答案:

答案 0 :(得分:466)

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

  • 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/

答案 1 :(得分:72)

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

  • 自己的界限(非框架)已更改。
  • 其中一个直接子视图的界限发生了变化。
  • 子视图将添加到视图中或从视图中删除。

一些相关细节:

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

答案 2 :(得分:16)

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

  

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

     

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

答案 3 :(得分:9)

BadPirate's answer中的一些要点只是部分正确:

  1. addSubView

      

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

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

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

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

  2. 对于设备旋转点

      

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

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

答案 4 :(得分:7)

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

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

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

答案 5 :(得分:7)

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

答案 6 :(得分:4)

你看过layoutIfNeeded吗?

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

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

- (void)layoutIfNeeded

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

状况 适用于iPhone OS 2.0及更高版本。

答案 7 :(得分:2)

将OpenGL应用程序从SDK 3迁移到4时,不再调用layoutSubviews。经过大量的反复试验后,我终于打开了MainWindow.xib,选中了Window对象,在检查器中选择了Window Attributes选项卡(最左边)并选中了“在启动时可见”。似乎在SDK 3中它仍然用于引起layoutSubViews调用,但不是4。

结束了6个小时的挫折。

答案 8 :(得分:0)

layoutSubviews永远不会被调用时,一个相当模糊但又可能很重要的案例是:

import UIKit

class View: UIView {

    override class var layerClass: AnyClass { return Layer.self }

    class Layer: CALayer {
        override func layoutSublayers() {
            // if we don't call super.layoutSublayers()...
            print(type(of: self), #function)
        }
    }

    override func layoutSubviews() {
        // ... this method never gets called by the OS!
        print(type(of: self), #function)
    }
}

let view = View(frame: CGRect(x: 0, y: 0, width: 100, height: 100))