ios 什么时候调用 layoutSubviews?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/728372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When is layoutSubviews called?
提问by Steve Weller
I have a custom view that's not getting layoutSubview
messages during animation.
我有一个自定义视图,layoutSubview
在动画过程中没有收到消息。
I have a view that fills the screen. It has a custom subview at the bottom of the screen that correctly resizes in Interface Builder if I change the height of the nav bar. layoutSubviews
is called when the view is created, but never again. My subviews are correctly laid out. If I toggle the in-call status bar off, the subview's layoutSubviews
is not called at all, even though the main view does animate its resize.
我有一个充满屏幕的视图。它在屏幕底部有一个自定义子视图,如果我更改导航栏的高度,它会在 Interface Builder 中正确调整大小。layoutSubviews
在创建视图时调用,但不再调用。我的子视图布局正确。如果我关闭通话状态栏,layoutSubviews
则根本不会调用子视图,即使主视图确实对其调整大小进行了动画处理。
Under what circumstances is layoutSubviews
actually called?
在什么情况下才layoutSubviews
真正被调用?
I have autoresizesSubviews
set to NO
for my custom view. And in Interface Builder I have the top and bottom struts and the vertical arrow set.
我已经autoresizesSubviews
设置NO
为我的自定义视图。在 Interface Builder 中,我设置了顶部和底部支柱以及垂直箭头。
Another part of the puzzle is that the window must be made key:
难题的另一部分是必须使窗口成为关键:
[window makeKeyAndVisible];
of else the subviews are not automatically resized.
否则子视图不会自动调整大小。
采纳答案by Steve Weller
I tracked the solution down to Interface Builder's insistence that springs cannot be changed on a view that has the simulated screen elements turned on (status bar, etc.). Since the springs were off for the main view, that view could not change size and hence was scrolled down in its entirety when the in-call bar appeared.
我将解决方案追溯到 Interface Builder 的坚持,即不能在打开模拟屏幕元素(状态栏等)的视图上更改弹簧。由于主视图的弹簧关闭,因此该视图无法更改大小,因此在呼叫栏出现时整个向下滚动。
Turning the simulated features off, then resizing the view and setting the springs correctly caused the animation to occur and my method to be called.
关闭模拟功能,然后调整视图大小并正确设置弹簧会导致动画发生并调用我的方法。
An extra problem in debugging this is that the simulator quits the app when the in-call status is toggled via the menu. Quit app = no debugger.
调试时的一个额外问题是,当通过菜单切换通话状态时,模拟器会退出应用程序。退出应用程序 = 没有调试器。
回答by BadPirate
I had a similar question, but wasn't satisfied with the answer (or any I could find on the net), so I tried it in practice and here is what I got:
我有一个类似的问题,但对答案(或我可以在网上找到的任何答案)不满意,所以我在实践中尝试了它,这是我得到的:
init
does not causelayoutSubviews
to be called (duh)addSubview:
causeslayoutSubviews
to be called on the view being added, the view it's being added to (target view), and all the subviews of the target- view
setFrame
intelligently callslayoutSubviews
on the view having its frame set only if the size parameter of the frame is different - scrolling a UIScrollView
causes
layoutSubviews
to be called on the scrollView, and its superview - rotating a device only calls
layoutSubview
on the parent view (the responding viewControllers primary view) - Resizing a view will call
layoutSubviews
on its superview
init
不会layoutSubviews
被称为(废话)addSubview:
导致layoutSubviews
在被添加的视图、它被添加到的视图(目标视图)以及目标的所有子视图上被调用- 视图
setFrame
智能电话layoutSubviews
上的图,其具有其帧组仅当所述帧的尺寸参数是不同 - 滚动 UIScrollView 导致
layoutSubviews
在 scrollView 及其超级视图上调用 - 旋转设备只调用
layoutSubview
父视图(响应的 viewControllers 主视图) - 调整视图大小将调用
layoutSubviews
其超视图
My results - http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-called/
我的结果 - http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-called/
回答by Patrick Pijnappel
Building on the previous answer by @BadPirate, I experimented a bit further and came up with some clarifications/corrections. I found that layoutSubviews:
will be called on a view if and only if:
在@BadPirate 的先前答案的基础上,我进行了进一步的实验并提出了一些澄清/更正。我发现layoutSubviews:
当且仅当以下情况下才会在视图上调用它:
- Its own bounds(not frame) changed.
- The bounds of one of its direct subviews changed.
- A subview is added to the view or removed from the view.
- 它自己的边界(不是框架)改变了。
- 其直接子视图之一的边界发生了变化。
- 一个子视图被添加到视图或从视图中删除。
Some relevant details:
一些相关细节:
- The bounds are considered changed only if the new value is different, including a different origin. Note specifically that is why
layoutSubviews:
is called whenever a UIScrollView scrolls, as it performs the scrolling by changing its bounds' origin. - Changing the frame will only change the bounds if the size has changed, as this is the only thing propagated to the bounds property.
- A change in bounds of a view that is not yet in a view hierarchy will result in a call to
layoutSubviews:
when the view is eventually added to a view hierarchy. - And just for completeness: these triggers do not directlycall layoutSubviews, but rather call
setNeedsLayout
, which sets/raises a flag. Each iteration of the run loop, for all views in the view hierarchy, this flag is checked. For each view where the flag is found raised,layoutSubviews:
is called on it and the flag is reset. Views higher up the hierarchy will be checked/called first.
- 仅当新值不同(包括不同的 origin )时才认为边界已更改。特别注意,这就是为什么
layoutSubviews:
在 UIScrollView 滚动时调用的原因,因为它通过更改其边界的原点来执行滚动。 - 如果大小发生变化,更改框架只会更改边界,因为这是传播到 bounds 属性的唯一内容。
- 尚未在视图层次结构中的视图边界的更改将导致在
layoutSubviews:
视图最终添加到视图层次结构时调用。 - 并且只是为了完整性:这些触发器不直接调用 layoutSubviews,而是调用
setNeedsLayout
,它设置/引发一个标志。运行循环的每次迭代,对于视图层次结构中的所有视图,都会检查此标志。对于每个发现标志升起的视图,在其layoutSubviews:
上调用并重置标志。将首先检查/调用层次结构更高的视图。
回答by frogcjn
Layout changes can occur whenever any of the following events happens in a view:
a. The size of a view's bounds rectangle changes.
b. An interface orientation change occurs, which usually triggers a change in the root view's bounds rectangle.
c. The set of Core Animation sublayers associated with the view's layer changes and requires layout.
d. Your application forces layout to occur by calling the?setNeedsLayout
?or?layoutIfNeeded
?method of a view.
e. Your application forces layout by calling the?setNeedsLayout
?method of the view's underlying layer object.
每当视图中发生以下任何事件时,都可能发生布局更改:
一种。视图边界矩形的大小发生变化。
湾 发生界面方向更改,这通常会触发根视图边界矩形的更改。
C。与视图层相关联的一组核心动画子层发生变化并需要布局。
d. 您的应用程序通过调用?setNeedsLayout
?或者?layoutIfNeeded
?一个视图的方法。
e. 您的应用程序通过调用?setNeedsLayout
? 视图底层对象的方法。
回答by Mohit Nigam
Some of the points in BadPirate's answerare only partially true:
BadPirate 的回答中的一些观点只是部分正确:
For
addSubView
pointaddSubview
causes layoutSubviews to be called on the view being added, the view it's being added to (target view), and all the subviews of the target.It depends on the view's (target view) autoresize mask. If it has autoresize mask ON, layoutSubview will be called on each
addSubview
. If it has no autoresize mask then layoutSubview will be called only when the view's (target View) frame size changes.Example: if you created UIView programmatically (it has no autoresize mask by default), LayoutSubview will be called only when UIView frame changes not on every
addSubview
.It is through this technique that the performance of the application also increases.
For the device rotation point
Rotating a device only calls layoutSubview on the parent view (the responding viewController's primary view)
This can be true only when your VC is in the VC hierarchy (root at
window.rootViewController
), well this is most common case. In iOS 5, if you create a VC, but it is not added into any another VC, then this VC would not get any noticed when device rotate. Therefore its view would not get noticed by calling layoutSubviews.
对于
addSubView
点addSubview
导致在被添加的视图、它被添加到的视图(目标视图)以及目标的所有子视图上调用 layoutSubviews。这取决于视图的(目标视图)自动调整大小掩码。如果它启用了自动调整大小掩码,则 layoutSubview 将在每个
addSubview
. 如果它没有自动调整大小掩码,则只有当视图的(目标视图)框架大小更改时才会调用 layoutSubview。示例:如果您以编程方式创建 UIView(默认情况下它没有自动调整大小掩码),则仅当 UIView 框架不是在每个
addSubview
.正是通过这种技术,应用程序的性能也得到了提高。
对于设备旋转点
旋转设备只在父视图(响应 viewController 的主视图)上调用 layoutSubview
只有当您的 VC 位于 VC 层次结构中(根在
window.rootViewController
)时,这才是正确的,这是最常见的情况。在 iOS 5 中,如果您创建了一个 VC,但没有将其添加到任何其他 VC 中,那么当设备旋转时,该 VC 将不会被注意到。因此,调用 layoutSubviews 不会注意到它的视图。
回答by bademi
calling
[self.view setNeedsLayout];
in viewController makes it to call viewDidLayoutSubviews
调用
[self.view setNeedsLayout];
viewController 使其调用 viewDidLayoutSubviews
回答by Willi Ballenthin
have you looked at layoutIfNeeded?
你看过 layoutIfNeeded 吗?
The documentation snippet is below. Does the animation work if you call this method explicitly during the animation?
文档片段如下。如果在动画期间显式调用此方法,动画是否有效?
layoutIfNeeded Lays out the subviews if needed.
layoutIfNeeded 根据需要布置子视图。
- (void)layoutIfNeeded
Discussion Use this method to force the layout of subviews before drawing.
讨论 使用此方法在绘图前强制子视图布局。
Availability Available in iPhone OS 2.0 and later.
可用性 在 iPhone OS 2.0 及更高版本中可用。
回答by Tal Yaniv
When migrating an OpenGL app from SDK 3 to 4, layoutSubviews was not called anymore. After a lot of trial and error I finally opened MainWindow.xib, selected the Window object, in the inspector chose Window Attributes tab (leftmost) and checked "Visible at launch". It seems that in SDK 3 it still used to cause a layoutSubViews call, but not in 4.
将 OpenGL 应用程序从 SDK 3 迁移到 4 时,不再调用 layoutSubviews。经过大量的反复试验,我终于打开了 MainWindow.xib,选择了 Window 对象,在检查器中选择了 Window Attributes 选项卡(最左侧)并选中了“启动时可见”。似乎在 SDK 3 中它仍然用于引起 layoutSubViews 调用,但在 4 中没有。
6 hours of frustration put to an end.
6个小时的挫折终于结束了。
回答by milos
A rather obscure, yet potentially important case when layoutSubviews
never gets called is:
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))