从Xcode 8和iOS10开始,viewDidLayoutSubviews上的视图大小不正确

Mar*_*tin 91 ios autolayout ios10 xcode8

似乎在Xcode 8上viewDidLoad,所有viewcontroller子视图都具有相同的1000x1000大小.奇怪的是,但没关系,viewDidLoad从来没有一个正确调整视图大小的好地方.

但是viewDidLayoutSubviews!

在我当前的项目中,我尝试打印按钮的大小:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    NSLog(@"%@", self.myButton);
}
Run Code Online (Sandbox Code Playgroud)

日志显示myButton的大小为(1000x1000)!然后,如果我登录按钮单击,例如,日志显示正常大小.

我正在使用autolayout.

这是一个错误吗?

Mar*_*tin 96

现在,Interface Builder允许用户动态更改故事板中每个视图控制器的大小,以模拟特定设备的大小.

在此功能之前,用户应手动设置每个视图控制器大小.因此视图控制器以一定的大小保存,用于initWithCoder设置初始帧.

现在,似乎initWithCoder不使用storyboard中定义的大小,并为viewcontroller视图及其所有子视图定义1000x1000像素大小.

这不是问题,因为视图应始终使用以下任一布局解决方案:

  • 自动布局,所有约束都将正确布局您的视图

  • autoresizingMask,它将布置没有附加任何约束的每个视图(注意自动布局和边距约束现在在同一视图中兼容\ o /!)

但是这对于与视图层相关的所有布局内容都是一个问题cornerRadius,因为自动布局和自动调整遮罩都不适用于图层属性.

要回答这个问题,通常的方法是使用,viewDidLayoutSubviews如果您在控制器中,或者layoutSubview如果您在视图中.此时(不要忘记调用他们的super相关方法),你很确定所有的布局都已经完成了!

确定吗?嗯...不完全,我已经说过,这就是我问这个问题的原因,在某些情况下,这个方法的视图仍然有1000x1000的大小.我认为我自己的问题没有答案.要提供有关它的最大信息:

1-只有在铺设细胞时才会发生!在UITableViewCell&UICollectionViewCell子类中,子视图被正确布局layoutSubview后将不会被调用.

2-正如@EugenDimboiu评论的那样(如果对你有用,请选择他的答案),调用[myView layoutIfNeeded]未布局的子视图将及时正确布局.

- (void)layoutSubviews {
    [super layoutSubviews];
    NSLog (self.myLabel); // 1000x1000 size 
    [self.myLabel layoutIfNeeded];
    NSLog (self.myLabel); // normal size
}
Run Code Online (Sandbox Code Playgroud)

3-对我来说,这绝对是一个错误.我已将它提交给雷达(id 28562874).

PS:我不是英国本地人,所以如果我的语法应该纠正,请随时编辑我的帖子;)

PS2:如果你有更好的解决方案,请随意不要写另一个答案.我会移动接受的答案.

  • thx,但我找不到id为28562874的雷达,我可以拥有雷达URL吗? (3认同)
  • 我要感谢您和其他所有人的见解和建议.我花了一整天时间把头发拉出来,因为``UICollectionViewCell`里面的`UIStackView`在`viewDidLayoutSubviews`期间没有返回正确的高度.调用`layoutIfNeeded`立即纠正了这个问题. (2认同)

Eug*_*oiu 40

您是否使用圆角作为按钮?尝试layoutIfNeeded()之前打电话.

  • 它可能在将来帮助某人,并且更容易发现与评论相比较 (4认同)

Der*_*ike 22

解决方案:里面裹一切viewDidLayoutSubviewsDispatchQueue.main.async.

// swift 3

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    DispatchQueue.main.async {
        // do stuff here
    }
}
Run Code Online (Sandbox Code Playgroud)


Han*_*ney 18

我知道这不是你的确切问题,但我遇到了一个类似的问题,尽管在viewDidLayoutSubviews中有一些正确的帧大小,我的一些观点仍然搞砸了.根据iOS 10发行说明:

"发送layoutIfNeeded到视图不会移动视图,但在早期版本中,如果视图已将translateAutoresizingMaskIntoConstraints设置为NO,并且如果它是通过约束定位的,则layoutIfNeeded将在发送布局之前移动视图以匹配布局引擎这些变化纠正了这种行为,接收者的位置和通常它的大小不会受到layoutIfNeeded的影响.

某些现有代码可能依赖于现在已更正的此错误行为.在iOS 10之前链接的二进制文件没有行为更改,但是在iOS 10上构建时,您可能需要通过将-layoutIfNeeded发送到前一个接收器的translatesAutoresizingMaskIntoConstraints视图的超级视图来纠正某些情况,或者之前定位和调整它的大小(或之后,取决于您所希望的行为)layoutIfNeeded.

使用自动布局的自定义UIView子类的第三方应用程序在调用超级之前覆盖layoutSubviews和self上的脏布局有可能在iOS 10上重建时触发布局反馈循环.当正确发送后续layoutSubviews调用时,他们必须确保在某些时候停止弄脏自己的布局(注意在iOS 10之前的版本中跳过了这个调用)."

基本上,如果使用translatesAutoresizingMaskIntoConstraints,则无法在View的子对象上调用layoutIfNeeded - 现在调用layoutIfNeeded必须在superView上,您仍然可以在viewDidLayoutSubviews中调用它.


Emi*_*iel 5

如果layoutSubViews中的框架不正确(不是),则可以在主线程上分派异步代码。这使系统有一些时间进行布局。当执行您分派的块时,框架具有适当的大小。