1. 程式人生 > >那些年我們一起追過的自動佈局Masonry(一)requiresConstraintBasedLayout

那些年我們一起追過的自動佈局Masonry(一)requiresConstraintBasedLayout

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

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

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

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

後來Github上的出現了基於UILayoutConstraint封裝的第三方佈局框架Masonry,Masonry使用起來非常方便。

什麼是Masonry

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

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

現在我們以Masonry中的UpdateConstraints為例,講解一下

#import "MASExampleUpdateView.h"

@interface MASExampleUpdateView ()

@property (nonatomic, strong) UIButton *growingButton;

@property (nonatomic

, assign) CGSize buttonSize;

@end

@implementation MASExampleUpdateView

- (id)init {

self = [superinit];

if (!self) returnnil;

self.growingButton = [UIButtonbuttonWithType:UIButtonTypeSystem];

    [self.growingButtonsetTitle:@"Grow Me!"forState:UIControlStateNormal];

self.growingButton.layer.borderColor = UIColor.greenColor.CGColor;

self.growingButton.layer.borderWidth = 3;

    [self.growingButtonaddTarget:selfaction:@selector(didTapGrowButton:) forControlEvents:UIControlEventTouchUpInside];

    [selfaddSubview:self.growingButton];

self.buttonSize = CGSizeMake(100, 100);

returnself;

}

+ (BOOL)requiresConstraintBasedLayout

{

returnYES;

}

// this is Apple's recommended place for adding/updating constraints

- (void)updateConstraints {

    [self.growingButtonupdateConstraints:^(MASConstraintMaker *make) {

        make.center.equalTo(self);

        make.width.equalTo(@(self.buttonSize.width)).priorityLow();

        make.height.equalTo(@(self.buttonSize.height)).priorityLow();

        make.width.lessThanOrEqualTo(self);

        make.height.lessThanOrEqualTo(self);

    }];

//according to apple super should be called at end of method

    [superupdateConstraints];

}

- (void)didTapGrowButton:(UIButton *)button {

self.buttonSize = CGSizeMake(self.buttonSize.width * 1.3, self.buttonSize.height * 1.3);

// tell constraints they need updating標記需要重新進行佈局

    [selfsetNeedsUpdateConstraints];

// update constraints now so we can animate the change呼叫此方法,如果標記為有需要重新佈局的約束,則立即進行重新佈局,內部會呼叫updateConstraints.

    [selfupdateConstraintsIfNeeded];

//佈局

    [UIViewanimateWithDuration:0.4animations:^{

        [selflayoutIfNeeded];

    }];

}

看到很多Autolayout寫的自定義控制元件中都實現了requiresConstraintBasedLayout方法,一直不知道這個方法有什麼用,因為不實現這個方法也沒發現有什麼影響。經過查詢資料,有解釋如下:
constraint-based layout engages lazily when someone tries to use it (e.g., adds a constraint to a view). If you do all of your constraint set up in -updateConstraints, you might never even receive updateConstraints if no one makes a constraint. To fix this chicken and egg problem, override this method to return YES if your view needs the window to use constraint-based layout.

意思就是基於約束的佈局是懶觸發的,只有在添加了約束的情況下,系統才會自動呼叫updateConstraints方法,如果把所有的約束放在 updateConstraints中,那麼系統將會不知道你的佈局方式是基於約束的,所以重寫requiresConstraintBasedLayout 返回YES就是明確告訴系統:雖然我之前沒有新增約束,但我確實是基於約束的佈局!這樣可以保證系統一定會呼叫 updateConstraints 方法 從而正確新增約束.

連結:http://www.jianshu.com/p/b58233a2c640
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。