尽管可能很简单,但我仍然发现自己正在努力解决正确的问题。
我试图了解在中找到 REAL UIView
(或任何其他子视图)框架的正确方法是什么使用自动布局时,viewDidLoad
。
主要问题是在viewDidLoad中,视图未应用其约束。我知道"已知"这种情况的答案是
override func viewDidLoad() {
super.viewDidLoad()
view.layoutIfNeeded()
stepContainer.layoutIfNeeded() // We need this Subview real frame!
let realFrame = stepContainer.frame
}
但我发现它并不总是有效,并且不时会给出错误的帧(即不是显示的最终帧)。
经过一些研究后,我发现在DispatchQueue.main.async { }
下扭曲此代码可以得到准确的结果。但是我不确定它是否是正确的处理方式,或者我是否使用此方法导致了一些引擎盖下的问题。决赛"工作"代码:
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.async {
self. stepContainer.layoutIfNeeded()
print(self. stepContainer.frame) // Real frame..
}
}
注意:我只需要从viewDidLoad中找到真正的帧,请不要建议使用viewDidAppear / layoutSubviews等。
答案 0 :(得分:6)
@DavidRönnqvist指出
调度异步的原因是这里给出“正确”值 它被安排在下一个运行循环中运行;在
viewWillAppear
之后 并且viewDidLayoutSubviews
已经运行。
示例强>
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.async {
print("DispatchQueue.main.async viewDidLoad")
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("viewWillAppear")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("viewDidAppear")
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print("viewDidLayoutSubviews")
}
viewWillAppear中
viewDidLayoutSubviews
viewDidAppear
DispatchQueue.main.async viewDidLoad
来自DispatchQueue.main.async
的{{1}}内的代码甚至在viewDidLoad
之后调用。因此,在viewDidAppear
中使用DispatchQueue.main.async
会为您提供正确的框架,但它不是最早的。
<强>答案强>
如果您希望尽早获得正确的框架,viewDidLoad
是正确的做法。
如果您必须在viewDidLayoutSubviews
内放置一些代码,那么您的做法是正确的。看起来像viewDidLoad
是最好的方法。
答案 1 :(得分:1)
阅读完评论后,也许您可以尝试将视图控制器嵌入另一个带容器的视图控制器中,并执行以下操作:
var viewSize : CGSize?
var parentViewSize : CGSize?
viewDidLayoutSubViews
中的尺寸并存储它:viewSize = view.size
prepareForSegue
发送您存储的尺寸:(destinationViewController as? MyViewController)?.parentViewSize = viewSize
viewDidLoad
您将访问parentViewSize
变量,其中包含良好的值会这样做吗?
答案 2 :(得分:1)
您的问题与this problem类似,我的回答也是一样的。
不保证viewDidLoad中的帧与最终显示视图时的帧相同。 UIKit会根据将出现的上下文调整视图控制器视图的框架,然后再显示它。为了更好地理解视图生命周期,您可以参考此图像。
该图片将帮助您了解代码的工作原理。如图所示,一旦加载了视图,就会调用viewWillAppear,当你设置dispatch async时,它会在执行viewWillAppear后异步添加到线程中。因此,一旦调用了viewWillAppear,您的框架就会根据您的视图进行更新,并且您可以在调度异步中获得正确的框架。
参考文献: Image source
For more information about view life cycle you can visit this answer
所以,最后,你可以选择以下两个选项之一:
希望这有帮助!