iOS8上的自动布局问题,使用在iOS7上正常工作的代码

24
我正在开发一款 iPhone 和 iPad 应用程序,它支持 iOS6 和 iOS7,并且它只使用自动布局。上周,当苹果宣布 iOS8 已经准备好投入使用时,我将我的一个 iPhone 和一个 iPad 升级到了 iOS8,同时将 XCODE 升级到了版本 6。我还有另一个 iPhone,仍然运行在 iOS7 上。我使用 Xcode 6 生成了新的可执行文件,当我在运行 iOS8 的设备上执行时,屏幕布局混乱了,但在 iOS7 上运行良好。这在我的物理设备和 Xcode 的模拟器上都是如此。经过大量挖掘,我现在非常清楚发生了什么,尽管我不知道为什么。具体来说,在 iOS8 上,我遇到了某些自动布局操作失败的问题,但在 iOS7 上则正常。例如,我想在底层视图上放置一个按钮,其大小等于屏幕的大小:(1) 如果我要求自动布局将按钮的水平中心(CX)与底层视图的水平中心相等,则结果是将按钮的水平中心放置在底层视图的左边缘。(2)如果我要求自动布局使按钮的宽度等于底层视图宽度的50%,则它根本没有宽度。我能够通过以下方式解决这些问题:(1) 我要求自动布局将按钮的中心位置设置为底层视图的左侧加上屏幕宽度的50%。(2) 我要求自动布局使按钮的宽度等于屏幕宽度的50%。通过这样的解决方法,我慢慢摆脱了这些问题,让自动布局代码在 iOS7 和 iOS8 上都能正常工作。但是我真的很想知道这里到底发生了什么。看起来自动布局无法确定底层视图的大小,因此需要该信息的自动布局计算会失败。但是,它确实知道视图的顶部和左侧边缘的位置,因此基于这些数据的计算会成功。这是一个庞大的应用程序,我已经为 iOS6 和 iOS7 编写了数百行自动布局代码,对我来说完美无缺。我已经调整和尝试了三天 iOS8,但我并没有比开始时更明智。有人有什么建议或想法吗?

我和你一样。不管怎样,看起来你的底层视图宽度从开始就是0,因此当你告诉按钮的中心X是底层视图的中心X时,按钮出现在左边缘。 - Zhang
1
是的,从目前我所看到的,一旦我开始在视图上放置控件,我就可以使用所有不同的自动布局关系变化来对齐这些控件。例如,一个按钮的水平中心可以与另一个按钮对齐,没有问题。 - Gallymon
我也应该提一下,我没有使用IB。所有我的自动布局代码都是通过直接构建NSLayoutConstraint/s来完成的。我一直都是这样做的,在iOS7中运行得非常完美。 - Gallymon
作为最新进展,我仍在努力解决这个问题,试图找出其中的根本原因。 - Gallymon
我花了一周的时间来查明为什么在iOS<6|7>上有效的自动布局在iOS8上失败了,但是我没有找到任何答案。我可以看到我的约束条件,因为我请求我的按钮在superview中居中,并且它们是正确的。但是,无论如何,iOS8都无法正确地放置按钮。我已经花了足够多的时间在这上面了,而且有简单的解决方法(如上所述),所以我要放弃了。靠不住的事情,苹果。 - Gallymon
1
请参见https://dev59.com/BF8e5IYBdhLWcg3wPIZ_#66qfEYcBWogLw_1b7hoA。 - smileyborg
3个回答

11

@robmayoff提供了一个很好的答案:https://dev59.com/BF8e5IYBdhLWcg3wPIZ_#26066992

实际上,在iOS8中,您不能再对视图调用setNeedsUpdateConstraintssetNeedsLayout来更新子视图的约束。

您必须在其约束更改的视图上调用这些方法。 这与iOS7向后兼容。

示例:

假设您有一个带有根视图self.view和名为containerView的子视图的ViewController。 containerView有一个NSLayoutConstraint附加到它上面,您想要更改它(在本例中是顶部空间)。

在iOS7中,您可以通过请求根视图进行新布局来更新VC中的所有约束:

self.containerView_TopSpace.constant = 0;
[self.view setNeedsUpdateConstraints];
[self.view setNeedsLayout];

iOS 8中,您需要在containerView上请求布局:

self.containerView_TopSpace.constant = 0;
[self.containerView setNeedsUpdateConstraints];
[self.containerView setNeedsLayout];

BFar,这是个好消息,也很有道理。我迫不及待地想试一试,看看能否解决这个问题。 - Gallymon
@BFar,您能否请提供一个简单的示例项目来演示这个问题(例如,在7 SDK上工作,但在8 SDK上不工作),然后提交一个radar并分享radar编号? - smileyborg
BFar,我尝试了robmayoff的想法,但它们似乎与我的问题无关。现在我已经找到了一个合法的解决方法,所以我会继续前进。谢谢! - Gallymon

3
您可能会发现这个问题的答案很有帮助: UICollectionView cell subviews do not resize 在大多数情况下,iOS7上正常工作但在iOS8上出现自动布局问题似乎源于根视图在iOS8中未正确调整大小,特别是当我们将translatesAutoresizingMaskIntoConstraints设置为NO时。对于我的视图,我能够在layoutSubviews(或任何适当的初始化程序具有正确边界)中设置根视图的框架,并解决了这个问题。
self.contentView.frame = CGRectInset(self.bounds, 0, 0);

如上面的答案所示,您也可以执行以下操作。
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;

在您开始使用代码设置自己的约束条件之前,请将translatesAutoresizingMaskIntoConstraints重置为NO。

绝对讨厌我们的大部分时间都被这些烦人的问题占用了。


Praneeth,谢谢你。我已经尝试过了,但它并没有解决我遇到的问题。 - Gallymon
嗯,很抱歉听到那没能帮上忙。在我的情况下,我有一些IB约束和运行时代码调整的混合,这解决了我的问题。祝你好运。 - Praneeth Wanigasekera

0
在我的情况下,问题与标记为UIView-Encapsulated-Layout-WidthUIView-Encapsulated-Layout-Height的约束有关。当我将它们移除时,一切都表现得好像我的视图大小为零,所有内容都居中于屏幕左上角。当我保留它们时,新的约束按预期工作。我还保留了标记为_UILayoutSupportConstraint的约束。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接