ios10:viewDidLoad框架宽度/高度未正确初始化

从升级到XCode8 GM和ios10以来,通过Interface Builder创build的所有视图都没有被正确初始化,直到比预期晚得多。 这意味着在viewDidLoad,cellForRowAtIndexPath,viewWillAppear等,帧大小设置为{1000,1000}为每个视图。 在某些时候,他们似乎是正确的,但是为时已晚。

遇到的第一个问题是常见的四处倒angular:

view.layer.cornerRadius = view.frame.size.width/2 

进一步的问题是依赖于帧大小的任何事情都在代码中进行计算。

 cellForRowAtIndexPath 

对于cellForRowAtIndexPath,框架大小在初始表格显示时失败,但是一旦您滚动它就可以正常工作。 willDisplayCell:forRowAtIndexPath也没有正确的帧大小。

我已经硬编码了一些值,但显然这是非常糟糕的代码实践,以及在我的项目中相当多。

有没有方法或地方获得正确的框架尺寸?

编辑

我发现使用高度/宽度约束而不是帧宽度高度更可靠。 这可能会增加需要很多新的IBOutlets来链接项目上的高度/宽度约束的开销。

现在我已经创build了一个UIView类别,让我直接访问视图的高度/宽度约束,而不需要IBOutlets。 为了最小的使用,小循环不应该是一个大问题。 对于没有宽度/高度约束创build的IB项目,结果不能保证。 可能返回0最好为常数,或更糟糕的。 此外,如果您没有高度/宽度限制,并且您的视图根据前导/尾随约束dynamicresize,则这将不起作用。

-viewDidLoad似乎具有正确的框架大小,但如果在此处进行修改,则通常会导致UI的可视化更改。

UIView的+ WidthHeightConstraints.h

 @interface UIView (WidthHeightConstraints) -(NSLayoutConstraint*)widthConstraint; -(NSLayoutConstraint*)heightConstraint; -(NSLayoutConstraint*)constraintForAttribute:(NSLayoutAttribute)attribute; @end 

UIView的+ WidthHeightConstraints.m

 #import "UIView+WidthHeightConstraints.h" @implementation UIView (WidthHeightConstraints) -(NSLayoutConstraint*)widthConstraint{ return [self constraintForAttribute:NSLayoutAttributeWidth]; } -(NSLayoutConstraint*)heightConstraint { return [self constraintForAttribute:NSLayoutAttributeHeight]; } -(NSLayoutConstraint*)constraintForAttribute:(NSLayoutAttribute)attribute { NSLayoutConstraint *targetConstraint = nil; for (NSLayoutConstraint *constraint in self.constraints) { if (constraint.firstAttribute == attribute) { targetConstraint = constraint; break; } } return targetConstraint; } @end 

编辑2

上面的类别已被certificate只是部分有效的。 主要是因为ios似乎自动添加一些额外的高度/宽度约束重复,这是NSContentSizeLayoutConstrainttypes,它实际上是不正常的约束相同的大小。 NSContentSizeLayoutConstraint也是一个私人类,所以我不能做isKindOfClass来过滤掉。 我还没有find另一种方法来有效地testing那些呢。 这很烦人

您所描述的最常见的问题仅在iOS 10中出现,可以通过添加以下代码来解决(如有必要):

 self.view.layoutIfNeeded() 

就在代码的上方,负责改变约束,layer.cornerRadius等

要么

将与帧/图层相关的代码放入viewDidLayoutSubviews()方法中:

 override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() view.layer.cornerRadius = self.myView.frame.size.width/2 view.clipsToBounds = true ... etc } 

我们创build了一个雷达(28342777(标记为28221021,但打开时重复)),类似的问题和我们得到的答复如下:

在Xcode 8中,一个完全约束的,没有错位的视图不再保存一个帧,以最小化差异,并支持自动更新IB中的帧。 ,这些视图会以1000×1000的占位符大小解码,但在第一次布局后parsing。在初始布局之前是否可以分配图像,并且在第一次布局地址之后将图像分配给图像视图?请发送示例以帮助我们进一步分析,谢谢!“

目前我们已经为他们提供了示例项目。 我的观察:

  • 我们曾经发生过从Xcode 7.x转换到Xcode 8.x的XIB的问题
  • 如果我们故意破坏XIB中的约束,那么viewDidLoad将得到预期的高度和宽度,而不是1000×1000。
  • 对我们来说,这是一个UIImageView,我们在这个UIImageView上应用了一些分层的方法来使它成为循环和使用masksToBounds。 如果我们设置masksToBounds = NO,那么我们一切工作正常。

虽然苹果声称它将成为Xcode 8的标准,将视图设置为1000×1000,但这种行为似乎并不一致。

希望这可以帮助。

我遇到了同样的问题,并试图通过提及以上build议而没有运气来解决它。

看来它应该是苹果解决的一个错误。 我终于find一个解决scheme,通过更改将XIB文档保存为Xcode 7.x格式,并将我的UI恢复正常。

直到苹果发布修补程序,我不想花时间在黑客攻击。

在这里输入图像说明 在这里输入图像说明

那么做什么:

 - (NSLayoutConstraint*)widthConstraint{ return [self constraintForAttribute:NSLayoutAttributeWidth]; } - (NSLayoutConstraint*)heightConstraint { return [self constraintForAttribute:NSLayoutAttributeHeight]; } - (NSLayoutConstraint*)constraintForAttribute:(NSLayoutAttribute)attribute { NSLayoutConstraint *targetConstraint = nil; for (NSLayoutConstraint *constraint in self.constraints) { //NSLog(@"constraint: %@", constraint); if (![constraint isKindOfClass:NSClassFromString(@"NSContentSizeLayoutConstraint")]) { if (constraint.firstAttribute == attribute) { targetConstraint = constraint; break; } } } return targetConstraint; } 

不应该依赖于什么时候放置视图的时间。 如果之前为你工作,那么出于纯粹的运气。 在UIKit中对此有很less的保证。 如果你依赖于视图的大小,那么正确的做法是在该视图中重写layoutSubviews ,并在那里调整你的东西。

即使在屏幕上完全呈现您的视图之后,仍然有许多条件可能导致视图的大小发生变化。 例如:双高度状态栏,iPad上的多任务,设备旋转等等。 因此,在特定的时间点做与框架相关的布局改变绝不是一个好主意。

我有完全相同的问题。 我有自定义的UITableViewCell子类,并使用clipsToBounds = YESself.iconView.layer.cornerRadius = self.iconView.frame.size.width/2给自己一个圆形的图像。 尝试从cellForRowAtIndexPathwillDisplayCell调用我的单元格configuration方法,都没有工作。

这是什么工作:
将你的分层代码移动到像这样的单元的-layoutSubviews方法中:

 -(void)layoutSubviews { [super layoutSubviews]; self.iconView.clipsToBounds = YES; self.iconView.layer.cornerRadius = self.iconView.frame.size.width/2; } 

之后,图像应该正确加载,你的分层代码也应该工作。

只在您的自动布局框中更新框架在这里输入图像说明