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

我有一个充满屏幕的视图。它在屏幕底部有一个自定义子视图,如果我改变导航栏的高度,它会在界面生成器中正确地调整大小。layoutSubviews在视图创建时被调用,但不会再次调用。我的子视图被正确地布局。如果我关闭in-call状态栏,子视图的layoutSubviews根本不会被调用,即使主视图会动画调整它的大小。

在什么情况下layoutSubviews会被调用?

我有autoresizesSubviews设置为NO为我的自定义视图。在界面构建器中,我有顶部和底部的支柱和垂直箭头集。


另一个难题是窗口必须被设置为键:

[window makeKeyAndVisible];

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


当前回答

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

For addSubView point addSubview 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.

其他回答

你看过layoutIfNeeded吗?

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

layoutIfNeeded 如果需要,则显示子视图。

- (void)layoutIfNeeded

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

可用性 支持iPhone OS 2.0及以上版本。

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

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.

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

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

在调试这是一个额外的问题,模拟器退出应用程序时,在呼叫状态是通过菜单切换。退出app =没有调试器。

基于@BadPirate之前的回答,我进行了进一步的尝试,并提出了一些澄清/更正。我发现layoutSubviews:将被调用在一个视图当且仅当:

它自己的边界(不是帧)改变了。 它的一个直接子视图的边界改变了。 子视图被添加到视图中或从视图中移除。

一些相关细节:

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 directly call 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.

调用 (自我。视图setNeedsLayout]; in viewController使它调用viewDidLayoutSubviews