使用Masonry搭建特殊布局時與xib的對比,masonry搭建時與xib

來源:互聯網
上載者:User

使用Masonry搭建特殊布局時與xib的對比,masonry搭建時與xib

之前只有比較淺的接觸過Masonry。項目中大多數的布局還是用xib中的AutoLayout與手碼的frame計算相結合,相信也會有很多項目和我一樣是這兩種布局的組合。其實xib各方面用的感覺都挺好,以前是效能問題,衝突問題飽受人詬病,但隨著蘋果的更新換代這些問題也逐漸趨向最小化。 我們團隊整改的主要原因是為了更細粒度的組件化。因為將一塊代碼複用到另一個頁面遠比從xib中拖幾個控制項到別的頁面來的要快,並且使用Masonry寫出來的代碼在控制項間關係上非常清晰便於理解。

普通的布局就略過不說了,這裡搭建一些較為特殊的布局。

如果你不是在董鉑然部落格園看到本文請點擊查看原文。

1.下方有三個UIView或UIButton,要隨時隨著螢幕寬度的變化(橫屏豎屏)始終保持等寬等高。

 

上面的右圖是xib下搭建,使用常規的Masonry文法完成布局的代碼是這樣的

    [redView mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.equalTo(self.view.mas_left).with.offset(0);        make.bottom.equalTo(self.view.mas_bottom).with.offset(0);        make.height.equalTo(@100);    }];        [blueView mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.equalTo(redView.mas_right).with.offset(0);        make.bottom.equalTo(self.view.mas_bottom).with.offset(0);        make.width.equalTo(redView.mas_width).with.offset(0);        make.height.equalTo(redView.mas_height).with.offset(0);    }];        [greenView mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.equalTo(blueView.mas_right).with.offset(0);        make.bottom.equalTo(self.view.mas_bottom).with.offset(0);        make.right.equalTo(self.view.mas_right).with.offset(0);        make.width.equalTo(blueView.mas_width).with.offset(0);        make.height.equalTo(blueView.mas_height).with.offset(0);    }];

代碼中可以看到具體的邏輯還是特別清晰的。可以清楚地瞭解各個控制項間的關係,基本上每一行代表著xib中的一根約束。

並且Masonry支援了一些省略和簡寫:

如果是兩個控制項的同一個位置(約束)之間的聯絡,括弧中可以唯寫以來的控制項約束可以省略;

如果約束依賴的是同一個控制項,那可以用and將兩個約束連在一行寫;

如果位移量offset是0,後面的with.offset(0)可以省略;

將上面的代碼最簡可以寫成如下

    [redView mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.and.bottom.equalTo(self.view);        make.height.equalTo(@100);    }];        [blueView mas_makeConstraints:^(MASConstraintMaker *make) {        make.bottom.and.width.and.height.equalTo(redView);        make.left.equalTo(redView.mas_right);    }];        [greenView mas_makeConstraints:^(MASConstraintMaker *make) {        make.bottom.and.width.and.height.equalTo(blueView);        make.right.equalTo(self.view);        make.left.equalTo(blueView.mas_right);    }];

註:對於這種幾個模組功能相似位置相近的,建議多包一層父控制項,便於整個組件的操作與抽離,並且可以從宏觀的角度看項目結構更加清晰。 

 

2.實現相互依賴的自動布局,背景View的高度由自己子控制項的Label能拉多長決定。

簡單的描述就是,label的左邊和頂部是依賴父控制項grayView的。但是父控制項grayView的底部是依賴子控制項Label的。

上面右圖是IB頁面搭建的AutoLayout,但是按照xib的搭建的思路寫出的代碼是有問題的。

    [grayView mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.and.top.equalTo(self.view).with.offset(50);        make.width.equalTo(@200);        make.bottom.equalTo(contentLbl).with.offset(10);    }];        [contentLbl mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.and.top.equalTo(grayView).with.offset(10);        make.right.equalTo(grayView).with.offset(-10);    }];

 上面的代碼會導致崩潰,原因就是上面的第4行依賴的contentLbl的約束還沒有搭建所以導致崩潰。在xib中會出現紅色箭頭的情況,就是約束錯誤,在將約束調整正確後紅色箭頭會變成黃色箭頭,就是約束正確。 但是使用Masonry與xib不同,xib出現錯誤可以容忍你改正,Masonry只要出現錯誤就會馬上崩潰。 因此對於這種相互依賴的約束,下面的還沒建立就要約束他看似無法完成,實際的解決方案就是用子控制項反過來依賴他也是可以的。 也就是說,你想讓父控制項依賴子控制項比他多10像素,和設定子控制項依賴父控制項比他少10像素是一個等價的概念,可以相互轉化。如果你是細心的網友,你會發現在xib中你雖然設定的是父控制項依賴子控制項,但實際的約束還是放在子控制項裡的。

修改後的代碼如下:

    [grayView mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.and.top.equalTo(self.view).with.offset(50);        make.width.equalTo(@200);    }];        [contentLbl mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.and.top.equalTo(grayView).with.offset(10);        make.right.equalTo(grayView).with.offset(-10);        make.bottom.equalTo(grayView).with.offset(-10);    }];

 

3.設定百分比的約束,即一個約束是另一個約束百分之多少。

這種約束一般適用於width和height。 對於螢幕的適配很有用,等於把以前算frame的思想加到了autoLayout裡。

    [grayView mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.and.top.equalTo(self.view).with.offset(50);//        make.width.equalTo(@200);        make.width.equalTo(self.view).multipliedBy(0.5).offset(0);    }];        [contentLbl mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.and.top.equalTo(grayView).with.offset(10);        make.right.equalTo(grayView).with.offset(-10);        make.bottom.equalTo(grayView).with.offset(-10);    }];

和原生的約束一樣,設定向量係數(比例)之後也可以再設定一個位移量。

 

4.設定約束的更新

當前的自動布局第三方庫有多種,Masonry相比來說也算是重量級的了。Masonry相比其他自動布局的庫最大的優點是在於約束的更新做的很好。

假設現在的約束是上面第2條時的約束,現在設定按鈕點擊更新約束代碼如下

- (IBAction)btnclick:(id)sender {    [self.grayView mas_updateConstraints:^(MASConstraintMaker *make) {        make.width.equalTo(@300);    }];    [UIView animateWithDuration:3.0 animations:^{        [self.grayView layoutIfNeeded];    }];}

如果給約束的變化設定約束,需要用UIView動畫的block將 layoutIfNeed包裹住。而不是直接將約束更新包裹住。

更新約束要注意mas_updateConstraints 和 mas_remakeConstraints 有本質區別。 前者update是保留之前的約束再添加你本次新增的約束。如果出現了相同的設定約束的方法,僅僅是值不同,則會直接替換掉原來的約束。  後者remake是直接把原來的全部幹掉,然後添加本次設定的約束。

所以update要注意的是不要用新的方法添加了約束會與之前的約束相衝突。而remake需要注意的是你在remake裡面寫的約束必須是一個完整的約束,因為之前的約束全清空了。

如果沒有完全弄清兩個方法的區別則可能會寫出以下代碼,這是錯誤的

- (IBAction)btnclick:(id)sender {    [self.grayView mas_updateConstraints:^(MASConstraintMaker *make) {        make.left.and.top.equalTo(self.view).with.offset(10);        make.width.equalTo(self.view).multipliedBy(0.5);    }];        [UIView animateWithDuration:3.0 animations:^{        [self.grayView layoutIfNeeded];    }];}

因為原來的make.width.equalTo(@200); 和本次的 make.width.equalTo(self.view).multipliedBy(0.5); 雖然都是設定width但是設定方法不同,所以會會新舊都保留導致衝突報錯。

如果你不是在董鉑然部落格園看到本文請點擊查看原文。

 

5.設定優先權和Label抗壓縮

有的時候Label的寬度或是內部字型發生變化的時候,可能會出現XX... 這種情況,這是因為Label被壓縮了。Masonry有抗壓縮的設定,並且這個設定和Masonry的優先順序priority息息相關。iOS9字型的變化導致很多Label出現... ,如果當初使用Masonry來設定布局並且設定了抗壓縮,那應該就可以完全避免此問題。

設定一個View,裡面有一個子控制項Label。

    [blackView mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.equalTo(self.view).with.offset(50);        make.top.equalTo(self.view).with.offset(300);        make.size.mas_equalTo(CGSizeMake(200, 50));    }];        [contentLbl2 mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.and.top.equalTo(blackView).with.offset(10);        make.right.equalTo(blackView).with.offset(-50);        make.height.equalTo(@30);    }];

上面的第一塊代碼就是搭建一個普通的父控制項,可以無視。下面一塊是Label的約束

如果這麼設定,右邊要比父控制項少50,所以Label的文字顯示不下,會被積壓。

 

但是如果加入一個約束:“width最少也大於200”,並且給這個約束設定優先權比 “右邊要比父控制項少50” 的優先順序高,代碼如下

    [contentLbl2 mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.and.top.equalTo(blackView).with.offset(10);        make.width.greaterThanOrEqualTo(@200).priority(900);        make.right.equalTo(blackView).with.offset(-50).priority(800);        make.height.equalTo(@30);    }];

第3行的優先順序大於第4行的優先順序 所以執行第3行,Label並沒有被擠壓。

 

抗壓縮還有另一種設定方法 

    [contentLbl2 mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.and.top.equalTo(blackView).with.offset(10);        make.right.equalTo(blackView).with.offset(-50).priority(990);        make.height.equalTo(@30);    }];        [contentLbl2 setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];

設定“右邊要比父控制項少50” 的優先順序為1000以下, 然後在下面再寫上一行水平方向抗壓縮的代碼。 這裡要注意上面的“右邊比父控制項少50”優先順序不能不寫,因為Masonry這種類型的代碼預設優先順序都是1000,而下面UILayoutPriorityRequired的優先順序也是1000,那麼下面的代碼就不起效果了。

 

其實還有更簡單的設定方法,不用寫水平方向抗壓縮,只需要將上面約束後面的優先順序改到750以下

    [contentLbl2 mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.and.top.equalTo(blackView).with.offset(10);        make.right.equalTo(blackView).with.offset(-50).priority(749);        make.height.equalTo(@30);    }];

因為優先順序750對應的優先順序枚舉是UILayoutPriorityDefaultHigh,可以理解成Masonry本身就有一種抗壓縮的保護,優先順序是750。

    [contentLbl2 setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal];

這行代碼應該是所有label預設存在的。

所以以後如果想讓Label抗壓縮,直接把優先順序設定到750以下就OK了。

 

總結:

1.Masonry的方法並不多,鏈式方法,每一個點文法都是返回一個約束對象,一個個特定的約束是這個對象的屬性。

2.Masonry不同於xib搭建約束出現紅色還能調整,前者一出現問題直接崩潰,將問題卡在開發階段。

3.Masonry建立約束前必須將父子關係搭建好,並且不能對還沒有設定約束的控制項添加依賴。

4.更新約束要弄清remake和update的區別。

未經授權不得轉載

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.