歡迎光臨
每天分享高質量文章

iOS 佈局進階:你真的會用 autolayout 麽?

作者:indulge_in
鏈接:https://www.jianshu.com/p/02a1cd16cc06

前言

iOS 開發發展至今已經相當成熟了。佈局的方式從 frame、size、center 到如今強大的 autolayout,將 UI 佈局儘量的“自動化”和“智慧化”,在很大程度上減少了程式員的工作量。

 

可能很多人體會過接手一個老專案通篇的 frame 是有多麼的痛苦。在現如今的開發中,性能沒那麼敏感的時候還是提倡使用自動佈局(比如 UITableview 的高度自適應用法),以減少大量的 UI 計算。

 

然而很多開發者可能寫出的自動佈局一點也不自動。

 

autolayout 可以理解為:給界面設定規則,讓界面隨著資料的變化而做出符合規則的變化。

本篇文章重在解決自動佈局中複雜的相互約束。

選擇佈局的工具

在“遙遠的”過去,相信大家都用過(或者見別人用過)UIKit 框架的下的 NSLayoutConstraint,用原生的layout 代碼體量之大讓人有些難以接受,好在大牛們寫了一些輪子照福大家,比如業界最有名氣的框架—— Masonry。這裡就不介紹 Masonry 的基礎用法了,相關的文件已經滿天飛了。

關於使用 xib、storyboard 還是純代碼佈局,大家可以根據開發專案的進度要求和開發者人數來決定,反正他們佈局的道理是一樣的。

 

為了直觀性,本文使用 xib 來進行描述。

intrinsicContentSize

首先,我們得搞清楚 intrinsicContentSize 是什麼。

 

一個 View 的約束確定需要兩個東西,一個是位置,一個是大小。在日常開發中,我們發現給 UILabel、UIImageView、UIButton 實體寫約束的時候,只需要給他們位置,而不需要給大小。這是因為它們指定了 intrinsicContentSize(可以理解為內部通過內容計算出了一個合理的大小,我們可以不用指定它)。

 

指定 intrinsicContentSize 方法:重寫 UIView 中的 -(CGSize)intrinsicContentSize: 方法,在需要改變這個值時呼叫:invalidateIntrinsicContentSize 方法,告知系統值已改變(我們可以自定義指定 intrinsicContentSize 的類)

 

所以,當我們不給這三種指定了 intrinsicContentSize 的控制元件的大小的時候,UI 還是不會出錯,而且可以通過 intrinsicContentSize 屬性獲取內部計算過後的大小。

模糊約束

模糊約束,就是 Masonry 中的 lessThanOrEqualTo、greaterThanOrEqualTo,也就是小於等於、大於等於,單獨使用模糊約束很簡單。

example:

 

 

需求:上圖中label寬度和高度遵循 intrinsicContentSize,但是長度不能超過父視圖。
實現:Label 距離左邊 10,縱向居中,距離右邊小於等於 10

優先級

優先級就是在兩個約束衝突的時候,優先滿足優先級高的約束。

 

example:

 

其實通常情況下的優先級的使用很簡單,這裡我要講的是視圖的優先級,如下圖

 

這兩個方法相信大家都不陌生(不管有沒有用過),他們派上用場的條件是:該視圖指定了intrinsicContentSize(固有大小),所以 UILabel、UIImageView、UIButton 都可以配置這幾個方法。

 

當然,這是在nib檔案裡面進行可視化的配置,在代碼裡面是這樣的(他們是 UIView 的方法):

- (void)setContentHuggingPriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
- (void)setContentCompressionResistancePriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);

  • contentHuggingPriority:拒絕變大優先級

  • ContentCompressionResistancePriority:拒絕縮小優先級

 

換言之,拒絕變大優先級越高,它就不會變大,拒絕縮小優先級越高,它就不會縮小(額,有點廢話的感覺)。舉個例子見道理:

 

example:

 

需求:A 和 B 相距 10pt,A 的寬度只能和文本一致(A 儘量遵守指定的 intrinsicContentSize)

 

實現:

 

step 1:先固定A和B的位置,然後他們相距10,把約束加上過後會報警告

 

step 2:我們做以下操作就能解決

 

當然,這隻是一個預設情況(提醒各位,不光是寫業務邏輯,寫佈局也需要考慮極限情況,這樣才能寫出完美的佈局),當A的文本變化的時候會這樣:

 

 

step3:以下的處理就順理成章了

 

當然,到目前為止算了完成了需求,但是在實際開發中還有一個問題需要考慮,就是A的內容過長,將B擠壓為0了(_)

 

 

step4:這時候,我們需要給B一個最小的寬度,避免“人間蒸發”,實現這個並沒有想象中的那麼簡單,方法也很多,下麵只講解一種:

結語

佈局的重點內容無非就以上講解的東西,它們單獨拎出來時,大家都覺得非常的簡單。是否能寫出一個完美無 bug 的佈局,往往需要結合它們使用(固定約束、模糊約束、優先級),當佈局元素很多且極其靈活的時候,才是考研 iOS 工程師佈局 UI 能力的時候。

赞(0)

分享創造快樂