TL;DR;
作为一般指南,自动布局并没有完成为视图提供尺寸的时间viewDidLoad
被称为(内部也不正确viewDidLayoutSubviews
)。在查询它们之前确保所有视图及其子视图都有正确的大小bounds
or frame
, do:
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
print(self.someSubview.frame) // gives correct frame
解释
有点违反直觉,将代码放入其中viewDidLayoutSubviews
并不意味着所有子视图都已通过自动布局指定了正确的大小。去引用该方法的文档:
但是,调用此方法并不表明视图的子视图的各个布局已被调整。
这意味着:里面viewDidLayoutSubviews
,只有第一个层次的子视图才会有正确的大小(即子视图,但不是“孙视图”)。
这是我创建的示例布局(红色视图是子视图,蓝色视图是孙视图)。
关于这个例子的几个要点:
-
所有视图均使用自动布局约束进行定位到它们的父视图(固定边距,但不是固定宽度),这允许它们根据我运行的模拟器的屏幕尺寸来增大或缩小。
- 我在故事板中使用了 iPhone 7 大小的视图控制器,并在 iPhone 7 Plus 模拟器上运行了该示例。这意味着我可以确定视图会有所增长,并使用它来确定视图是否具有其原始大小或最终大小。
请注意,在 Interface Builder 中,子视图(红色)的原始宽度为 240 点,孙视图(蓝色)的原始宽度为 200 点。
这是代码:
class ViewController: UIViewController {
@IBOutlet weak var childView: UIView!
@IBOutlet weak var grandchildView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
print("child ", #function, childView.frame.size.width)
print("grandchild", #function, grandchildView.frame.size.width)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print("child ", #function, childView.frame.size.width)
print("grandchild", #function, grandchildView.frame.size.width)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("child ", #function, childView.frame.size.width)
print("grandchild", #function, grandchildView.frame.size.width)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("child ", #function, childView.frame.size.width)
print("grandchild", #function, grandchildView.frame.size.width)
}
}
这是输出:
child viewDidLoad() 240.0
grandchild viewDidLoad() 200.0
child viewWillAppear 240.0
grandchild viewWillAppear 200.0
child viewDidLayoutSubviews() 271.0 // `child` has it's final width now
grandchild viewDidLayoutSubviews() 200.0 // `grandchild` still has it's original width!
// By now, in MOST cases, all views will have their correct sizes.
child viewDidAppear 271.0
grandchild viewDidAppear 231.0
从这个输出中你可以看到的是viewDidLayoutSubviews
does not确保视图控制器主视图的直接子视图之后的任何内容都具有正确的大小。
Note:一般到时候viewDidAppear
被称为,视图有正确的大小,但我想说这是绝不保证.