簡體   English   中英

強制自動布局以在viewDidLoad上正確更新UIView框架

[英]Force Auto layout to update UIView frame correctly at viewDidLoad

雖然它很簡單,但我仍然發現自己正在努力解決正確的問題。

我試圖了解在使用自動布局時在viewDidLoad找到REAL UIView (或任何其他子視圖)幀的正確方法是什么。

主要問題是在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等。

正如@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")
}

viewWillAppear中

viewDidLayoutSubviews

viewDidAppear

DispatchQueue.main.async viewDidLoad

來自viewDidLoad DispatchQueue.main.async代碼甚至在viewDidAppear之后調用。 因此,在viewDidLoad使用DispatchQueue.main.async會為您提供正確的幀,但它不是最早的幀。

回答

  • 如果你想盡早獲得正確的框架, viewDidLayoutSubviews是正確的做法。

  • 如果你必須viewDidLoad放入一些代碼,那么你正在做正確的方法。 看起來像DispatchQueue.main.async是最好的方法。

閱讀完評論后,也許您可​​以嘗試將視圖控制器嵌入另一個帶有容器的視圖控制器中並執行以下操作:

  • 在父視圖控制器中添加一個變量: var viewSize : CGSize?
  • 在子視圖控制器中添加一個變量: var parentViewSize : CGSize?
  • 在父視圖控制器中,獲取viewDidLayoutSubViews的大小並存儲它: viewSize = view.size
  • 在父視圖控制器中,在prepareForSegue發送您存儲的大小: (destinationViewController as? MyViewController)?.parentViewSize = viewSize
  • 在子視圖控制器中,在viewDidLoad您將訪問具有良好值的parentViewSize變量

它會這樣做嗎?

你的問題與這個問題類似,我的回答也是一樣的。

在viewDidLoad中,不保證框架與最終顯示視圖時的框架相同。 UIKit會根據將出現的上下文調整視圖控制器視圖的框架,然后再顯示它。 為了更好地理解視圖生命周期,您可以參考此圖像。 在此輸入圖像描述

該圖像將幫助您了解代碼的工作原理。 如圖所示,一旦加載了視圖,就會調用viewWillAppear,當你設置dispatch async時,它會在執行viewWillAppear后異步添加到線程中。 因此,一旦調用了viewWillAppear,您的框架就會根據您的視圖進行更新,並且您可以在調度異步中獲得正確的框架。

參考文獻: 圖像源

有關視圖生命周期的更多信息,您可以訪問此答案

所以,最后,你可以選擇以下兩種方案之一:

  1. 如果要使用自動布局,請在viewDidLayoutSubviews或viewWillAppear中管理幀。 (在這些viewDidLayoutSubview中的任何一個都應該去,因為每次你的視圖位於視圖層次結構頂部時都會調用viewWillAppear,它不應該是首選的)。
  2. 如果您要跳過自動布局,則可以以編程方式創建和維護視圖。

希望這可以幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM