1. 程式人生 > >iOS自動佈局框架-Masonry詳解

iOS自動佈局框架-Masonry詳解

目前iOS開發中大多數頁面都已經開始使用Interface Builder的方式進行UI開發了,但是在一些變化比較複雜的頁面,還是需要通過程式碼來進行UI開發的。而且有很多比較老的專案,本身就還在採用純程式碼的方式進行開發。

而現在iPhone和iPad螢幕尺寸越來越多,雖然開發者只需要根據螢幕點進行開發,而不需要基於畫素點進行UI開發。但如果在專案中根據不同螢幕尺寸進行各種判斷,寫死座標的話,這樣開發起來是很吃力的。

所以一般用純程式碼開發UI的話,一般都是配合一些自動化佈局的框架進行螢幕適配。蘋果為我們提供的適配框架有:VFL、UIViewAutoresizing、Auto Layout、Size Classes等。

其中Auto Layout是使用頻率最高的佈局框架,但是其也有弊端。就是在使用UILayoutConstraint的時候,會發現程式碼量很多,而且大多都是重複性的程式碼,以至於好多人都不想用這個框架。

後來Github上的出現了基於UILayoutConstraint封裝的第三方佈局框架Masonry,Masonry使用起來非常方便,本篇文章就詳細講一下Masonry的使用。

Masonry介紹

這篇文章只是簡單介紹Masonry,以及Masonry的使用,並且會舉一些例子出來。但並不會涉及到Masonry的內部實現,以後會專門寫篇文章來介紹其內部實現原理,包括順便講一下鏈式語法。

什麼是Masonry

Masonry是一個對系統NSLayoutConstraint進行封裝的第三方自動佈局框架,採用鏈式程式設計的方式提供給開發者API。系統AutoLayout支援的操作,Masonry都支援,相比系統API功能來說,Masonry是有過之而無不及。

Masonry採取了鏈式程式設計的方式,程式碼理解起來非常清晰易懂,而且寫完之後程式碼量看起來非常少。之前用NSLayoutConstraint寫很多程式碼才能實現的佈局,用Masonry最少一行程式碼就可以搞定。下面看到Masonry的程式碼就會發現,太簡單易懂了。

Masonry是同時支援Mac和iOS兩個平臺的,在這兩個平臺上都可以使用Masonry進行自動佈局。我們可以從MASUtilities.h檔案中,看到下面的定義,這就是Masonry通過巨集定義的方式,區分兩個平臺獨有的一些關鍵字。

18.png

整合方式

Masonry支援CocoaPods,可以直接通過podfile檔案進行整合,需要在CocoaPods中新增下面程式碼:

1 pod 'Masonry'

Masonry學習建議

在UI開發中,純程式碼和Interface Builder我都是用過的,在開發過程中也積累了一些經驗。對於初學者學習純程式碼AutoLayout,我建議還是先學會Interface Builder方式的AutoLayout,領悟蘋果對自動佈局的規則和思想,然後再把這套思想巢狀在純程式碼上。這樣學習起來更好入手,也可以避免踩好多坑。

在專案中設定的AutoLayout約束,起到對檢視佈局的標記作用。設定好約束之後,程式執行過程中建立檢視時,會根據設定好的約束計算frame,並渲染到檢視上。

所以在純程式碼情況下,檢視設定的約束是否正確,要以執行之後顯示的結果和列印的log為準。

Masonry中的坑

在使用Masonry進行約束時,有一些是需要注意的。

  1. 在使用Masonry新增約束之前,需要在addSubview之後才能使用,否則會導致崩潰。

  2. 在新增約束時初學者經常會出現一些錯誤,約束出現問題的原因一般就是兩種:約束衝突和缺少約束。對於這兩種問題,可以通過除錯和log排查。

  3. 之前使用Interface Builder新增約束,如果約束有錯誤直接就可以看出來,並且會以紅色或者黃色警告體現出來。而Masonry則不會直觀的體現出來,而是以執行過程中崩潰或者列印異常log體現,所以這也是手寫程式碼進行AutoLayout的一個缺點。

這個問題只能通過多敲程式碼,積攢純程式碼進行AutoLayout的經驗,慢慢就用起來越來越得心應手了。

Masonry基礎使用

Masonry基礎API

1 2 3 4 5 6 7 8 9 mas_makeConstraints()    新增約束 mas_remakeConstraints()  移除之前的約束,重新新增新的約束 mas_updateConstraints()  更新約束 equalTo()       引數是物件型別,一般是檢視物件或者mas_width這樣的座標系物件 mas_equalTo()   和上面功能相同,引數可以傳遞基礎資料型別物件,可以理解為比上面的API更強大 width()         用來表示寬度,例如代表view的寬度 mas_width()     用來獲取寬度的值。和上面的區別在於,一個代表某個座標系物件,一個用來獲取座標系物件的值

Auto Boxing

上面例如equalTo或者width這樣的,有時候需要涉及到使用mas_字首,這在開發中需要注意作區分。

如果在當前類引入#import "Masonry.h"之前,用下面兩種巨集定義宣告一下,就不需要區分mas_字首。

1 2 3 4 // 定義這個常量,就可以不用在開發過程中使用"mas_"字首。 #define MAS_SHORTHAND // 定義這個常量,就可以讓Masonry幫我們自動把基礎資料型別的資料,自動裝箱為物件型別。 #define MAS_SHORTHAND_GLOBALS

修飾語句

Masonry為了讓程式碼使用和閱讀更容易理解,所以直接通過點語法就可以呼叫,還添加了and和with兩個方法。這兩個方法內部實際上什麼都沒幹,只是在內部將self直接返回,功能就是為了更加方便閱讀,對程式碼執行沒有實際作用。

例如下面的例子:

1 make.top.and.bottom.equalTo(self.containerView).with.offset(padding);

其內部程式碼實現,實際上就是直接將self返回。

1 2 3 - (MASConstraint *)