代码之家  ›  专栏  ›  技术社区  ›  Steve Weller

何时调用LayoutSubview?

  •  243
  • Steve Weller  · 技术社区  · 16 年前

    我有一个自定义视图 layoutSubview 动画期间的消息。

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

    在什么情况下 布局子视图 真的打过电话?

    我有 autoresizesSubviews 设置为 NO 对于我的自定义视图。在InterfaceBuilder中,我有顶部和底部的支柱和垂直箭头集。

    10 回复  |  直到 6 年前
        1
  •  459
  •   nburk    10 年前

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

    • init 不引起 layoutSubviews 到 被称为(DUH)
    • addSubview: 原因 布局子视图 在 正在添加的视图,它的视图 添加到(目标视图),以及所有 目标的子视图
    • 看法 setFrame 明智地打电话 布局子视图 在 仅设置其框架的视图 如果帧的大小参数为 不同的
    • 滚动uiScrollView 原因 布局子视图 被召唤 滚动视图及其超级视图
    • 仅旋转设备调用 layoutSubview 在父视图上 响应视图控制器主 视图)
    • 调整视图大小将调用 布局子视图 在它的超视图上

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

        2
  •  67
  •   Patrick Pijnappel    6 年前

    基于@badparit之前的回答,我做了进一步的实验,并提出了一些澄清/更正。我发现 layoutSubviews: 只有在以下情况下才会对视图调用:

    • 它自己 界限 (非框架)已更改。
    • 其中一个子视图的边界已更改。
    • 子视图将添加到视图或从视图中删除。

    一些相关细节:

    • 只有当新值不同时,边界才会被视为更改, 包括不同的起源 . 特别注意这就是为什么 LayOutSubVIEW: 每当UIScrollView滚动时调用,因为它通过更改其边界的原点来执行滚动。
    • 更改帧将仅在大小发生更改时更改边界,因为这是唯一传播到Bounds属性的内容。
    • 尚未在视图层次结构中的视图边界更改将导致调用 LayOutSubVIEW: 当视图最终添加到视图层次结构时 .
    • 为了完整性:这些触发器不会 直接地 调用layoutSubviews,而不是调用 setNeedsLayout 设置/升起标志。所有视图的运行循环的每次迭代 在视图层次结构中 ,此标志被选中。对于每个被发现提升了标志的视图, LayOutSubVIEW: 对其调用并重置标志。将首先检查/调用更高层次结构的视图。
        3
  •  14
  •   jscs    9 年前

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

    每当发生下列任何事件时,都可能发生布局更改 一种观点:

    A.视图的边框矩形的大小会发生变化。
    b.发生界面方向更改,通常会触发根视图的边界矩形更改。
    c.与视图层关联的核心动画子层集更改并需要布局。
    d.您的应用程序强制通过调用_进行布局。 setNeedsLayout α或γ layoutIfNeeded 视图方法。
    e.通过调用_ 设置需求布局 _视图_稊的底层对象的方法。

        4
  •  9
  •   Community CDub    8 年前

    其中一些要点 BadPirate's answer 仅部分正确:

    1. 为了 addSubView 指向

      addSubview 导致对要添加的视图、要添加的视图(目标视图)以及目标的所有子视图调用layoutSubview。

      它取决于视图的(目标视图)自动调整大小掩码。如果打开了AutoResize蒙版,则将对每个蒙版调用layoutSubview。 附加子视图 .如果它没有autoresize掩码,那么只有当视图(目标视图)的帧大小更改时,才会调用layoutSubview。

      示例:如果以编程方式创建uiview(默认情况下它没有autoresize掩码),则只有当uiview帧更改时才会调用layoutSubview,而不是在 附加子视图 .

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

    2. 对于设备旋转点

      旋转设备只调用父视图(响应视图控制器的主视图)上的layoutSubView。

      只有当您的vc在vc层次结构中时(根位于 window.rootViewController 这是最常见的情况。在iOS5中,如果您创建了一个VC,但它没有添加到任何其他VC中,那么当设备旋转时,这个VC就不会得到任何注意。因此,调用layoutSubview不会注意到它的视图。

        5
  •  7
  •   Steve Weller    16 年前

    我跟踪解决方案直到Interface Builder坚持在打开模拟屏幕元素(状态栏等)的视图上不能更改弹簧。由于主视图的Spring已关闭,因此该视图无法更改大小,因此当出现In调用栏时,该视图将整体向下滚动。

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

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

        6
  •  7
  •   bademi    11 年前

    打电话 [self.view setNeedsLayout]; 在ViewController中,使其调用ViewDidLayoutSubView

        7
  •  4
  •   Willi Ballenthin    16 年前

    你是否考虑过必要的裁员?

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

    需要整理的 如果需要,请列出子视图。

    - (void)layoutIfNeeded
    

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

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

        8
  •  2
  •   Tal Yaniv    15 年前

    当将OpenGL应用程序从sdk 3迁移到4时,不再调用layoutSubview。经过多次尝试和错误之后,我终于打开了mainwindow.xib,选择了window对象,在inspector中选择了window属性选项卡(最左边)并选中了“启动时可见”。在sdk 3中,它似乎仍然用于引起layoutSubviews调用,但在4中没有。

    6个小时的挫折终于结束了。

        9
  •  0
  •   Steve Weller    15 年前

    拼图的另一个部分是窗口必须是键:

    [window makeKeyAndVisible];
    

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

        10
  •  0
  •   Milos    7 年前

    一个相当模糊但潜在重要的案例 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))