動態新增子檢視 UIView 的正確方法

發表於2016-05-18

很多時候哥比較喜歡用程式碼新增檢視,特別是要同時加很多UIView時,而且跟 xib 比起來程式碼更容易管理,在多人的專案中程式碼不容易 conflict。

但小牛哥最近發現很多新人都不太清楚正確的使用方法,以下是哥的一些總結,有何不妥歡迎大家一起討論:

(前提條件是這樣的:有一個 View Controller  和相應的 xib 檔案,我們需要為這個controller 動態加上其他的子檢視)

UIViewController 中動態新增 UIView 正確的步驟應該是:

1. 在 viewDidLoad   中建立要新增的 UIView (UILabel, UIImageView, UIButton 等等)。像這樣: UIButton *aButton = [[UIButton alloc] initWithFrame:…] 為什麼不能在 viewWillAppear 中建立?根據蘋果的文件,這裡是新增 last minute 修改的地方,比如修改檢視的位置,顏色等等。如果在這裡建立很多檢視,會導致顯示延遲。

2. 建立的時候最好為每個 UIView 加上約束(NSLayoutConstraint),這樣在不同大小的螢幕中都可以正確顯示。

3. 不用約束也行,必須在 viewDidLayoutSubviews 中修改檢視的 frame。

對於一些簡單的檢視確實沒必要加上約束,但是沒有約束會導致檢視在不同大小的螢幕中的 frame 不好看,這時就得在這裡修改 frame, 對,只能在這裡: viewDidLayoutSubviews 裡修改。

為什麼呢?

首先我們來複習一下 UIViewController 的生命週期:

A: init…

B: loadView

C: viewDidLoad

D: viewWillAppear

E: viewWillLayoutSubviews

F: viewDidLayoutSubviews

G: viewDidAppear

H: viewWillDisappear

I: viewDidDisappear

J: viewDidUnload (not used any more)

K: dealloc…

 

現在我們可以做個實驗: 在專案中選一個View Contorller ,它的 xib 中的檢視大小為 600×600, 在其 .m 檔案中以上的 C, D,E,F,G方法列印出檢視的frame,像這樣:

選擇裝置為 iPhone 5, 執行程式後會得到類似這樣的結果:

大家可以看到,一個檢視的大小是在呼叫 viewWillLayoutSubviews 時才會根據裝置而改變,不過在 IOS 8 中,要到viewDidLayoutSubviews 才正確。根檢視的大小改變了,子檢視必須相應做出調整才可以正確顯示,這就是為什麼要在 viewDidLayoutSubviews 中調整動態檢視的frame。

By the way,在 IOS 9 中,根檢視控制元件(Root View Controller)的檢視大小在 viewDidLoad 中就已經正確了,蘋果好像會不時改變這些特點,比如會把系統鍵盤的檢視優先順序提高等等。所以小牛哥覺得動態新增檢視最安全的方法是,建立檢視後馬上加上約束,不管日後蘋果怎麼改都可以正確顯示。

關於如何動態新增約束,大家可以看看這裡:

http://matthewmorey.com/creating-uiviews-programmatically-with-auto-layout/

相關文章