强制自动布局以在viewDidLoad上正确更新UIView框架

Roi*_*lia 2 uiview viewdidload ios autolayout swift

虽然它很简单,但我仍然发现自己正在努力解决正确的问题.

我试图了解在使用自动布局时,在内部找到REAL(或任何其他子视图)帧的正确方法是什么. UIViewviewDidLoad

主要问题是在viewDidLoad中,视图未应用其约束.我知道这种情况的"已知"答案是

override func viewDidLoad() {
        super.viewDidLoad()
     view.layoutIfNeeded()
     stepContainer.layoutIfNeeded() // We need this Subview real frame!
     let realFrame = stepContainer.frame
}
Run Code Online (Sandbox Code Playgroud)

但我发现它并不总是有效,并且不时会给出错误的帧(即不是显示的最终帧).

经过一番研究后,我发现歪曲这段代码可以DispatchQueue.main.async { }得到准确的结果.但是我不确定这是否是正确的处理方法,或者我是否使用此方法导致了一些引擎盖下的问题.最终"工作"代码:

override func viewDidLoad() {
        super.viewDidLoad() 

        DispatchQueue.main.async {
            self. stepContainer.layoutIfNeeded()
            print(self. stepContainer.frame) // Real frame..
        }

}
Run Code Online (Sandbox Code Playgroud)

注意:我只需要从viewDidLoad中找到真正的帧,请不要建议使用viewDidAppear/layoutSubviews等.

tru*_*duc 6

正如@DavidRönnqvist指出的那样

dispatch async给你"正确"值的原因是它被安排在下一个运行循环中运行; 之后viewWillAppearviewDidLayoutSubviews已运行.

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")
}
Run Code Online (Sandbox Code Playgroud)

viewWillAppear中

viewDidLayoutSubviews

viewDidAppear

DispatchQueue.main.async viewDidLoad

代码中DispatchQueue.main.asyncviewDidLoad甚至被称为后viewDidAppear.所以使用DispatchQueue.main.asyncin viewDidLoad会给你正确的框架,但它不是最早的.

回答

  • 如果你想尽早获得正确的框架viewDidLayoutSubviews,那么这是正确的做法.

  • 如果你必须在里面放一些代码viewDidLoad,你就是在做正确的方法.似乎DispatchQueue.main.async是最好的方法.