使用masonry進行布局構(gòu)建的時候,代碼邏輯往往比較長抠刺。在布局頁面時往往會有嵌套的情況發(fā)生叶堆,組件的創(chuàng)建代碼就和布局代碼交織在一起阱飘,一段代碼看起來更是復(fù)雜,讓人難以理解。
本文僅僅通過一些UI寫法上的調(diào)整讓整體UI布局易讀沥匈、易改蔗喂。如果你有同樣的問題,耐心花5分鐘讀完高帖,稍加實踐即可事半功倍缰儿。
為了應(yīng)對這樣的情況,通常的做法是將UI構(gòu)建代碼寫在上面散址,布局代碼全部寫在最后(布局的組件必須先要被添加到父組件上)乖阵,這樣的好處是構(gòu)建和布局分開了,看起來似乎整齊了一些预麸,但是調(diào)試幾乎是災(zāi)難性的瞪浸,實踐一段時間后發(fā)現(xiàn)一些難以解決的問題。
一吏祸、遇到的問題:
1.元素分散不內(nèi)聚
原本頁面構(gòu)建時对蒲,會根據(jù)設(shè)計結(jié)構(gòu)先把一個大的頁面分割成幾部分,然后分別進行布局贡翘。在實踐中蹈矮,由于純代碼代碼量多,所以大多數(shù)情況下往往能少寫組件就少寫鸣驱,這樣原本該通過添加適當?shù)母竀iew去分離的UI結(jié)構(gòu)就不會去分離泛鸟,導(dǎo)致各個組件之間關(guān)系過緊密,不利于后期的修改丐巫,相似UI復(fù)用不易谈况。
2.命名困難
由于布局在一起,則每個組件都應(yīng)該有自己有意義的名稱递胧,往往導(dǎo)致命名困難碑韵。但大多數(shù)都只是在布局中使用一次,動態(tài)變化的少缎脾。這樣也不利于讀代碼祝闻。
二、一種最佳實踐
經(jīng)過一段時間的實踐和總結(jié)遗菠,找到一種比較清晰的寫法:
1.利用{}
構(gòu)成代碼塊對每一個組件進行分離
2.在每個代碼塊中將布局代碼寫在最后
3.每個子view都盡可能的之依托于自己的父組件進行布局
舉例說明:
中間有個view联喘,view中有兩個label, 一個居上,一局下辙纬,效果如圖
代碼如下:
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *bgView = [[UIView alloc] init];
{
[self.view addSubview:bgView];
bgView.backgroundColor = [UIColor blackColor];
UILabel *label1 = [[UILabel alloc] init];
{
[bgView addSubview:label1];
self.nameLabel = label1;
label1.font = [UIFont systemFontOfSize:18];
label1.textAlignment = NSTextAlignmentCenter;
label1.textColor = [UIColor systemYellowColor];
[label1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.mas_equalTo(0);
}];
}
UILabel *label2 = [[UILabel alloc] init];
{
[bgView addSubview:label2];
self.infoLabel = label2;
label2.textColor = [UIColor whiteColor];
label1.textAlignment = NSTextAlignmentCenter;
[label2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.left.right.mas_equalTo(0);
}];
}
[bgView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(0);
make.size.mas_equalTo(CGSizeMake(200, 200));
}];
}
self.nameLabel.text = @"Jack";
self.infoLabel.text = @"Jack is a good student";
}
三豁遭、寫法說明:
1.每一個組件本身都使用{}
進行封閉,在封閉區(qū)域的最上面寫添加到父組件代碼贺拣,然后是該組件本身的屬性設(shè)置蓖谢,賦值全局變量等捂蕴。在最下面寫布局代碼。如果還有子組件闪幽,就寫在兩者之間(截選上方代碼部分):
UIView *bgView = [[UIView alloc] init];
{
[self.view addSubview:bgView];
bgView.backgroundColor = [UIColor blackColor];
// 這里添加子組件
[bgView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(0);
make.size.mas_equalTo(CGSizeMake(200, 200));
}];
}
子組件寫法同理啥辨,一個子組件可以命名隨意一點不必十分有意義,比如leftLabel盯腌、rightLabel溉知、label1、label2等腕够。
因為頁面結(jié)構(gòu)復(fù)雜以后级乍,層級會很多,不少組件其實本身只是用于定位燕少、占位或者分隔等卡者,這樣可以極大的簡化命名也不影響對代碼的理解(用于需要保留到全局的變量仍然需要使用有意義的命名)對動態(tài)賦值的元素放到最下面進行 賦值 或 邏輯處理。不變的內(nèi)容放在布局代碼中賦值客们。
四、可能的疑問
1.為什么不將組件的聲明也放到代碼塊中材诽?
組件之間往往有約束關(guān)系底挫,全部放到代碼塊中再要使用需要將其放到全局變量中進行引用,這樣別的代碼塊中才能訪問到脸侥,違背了初衷建邓。
2.為什么不把UI的創(chuàng)建拆分成一個個的方法調(diào)用,在方法內(nèi)部去寫布局睁枕?
通過這樣的方式構(gòu)建UI官边,表面看起來可以簡化一部分代碼,但是缺點也是顯而易見的:
方法要接收父組件作為參數(shù)(需要添加到父組件上才能設(shè)置約束外遇,否則會報錯)注簿,同時,如果需要參考其他元素的位置跳仿,那么方法的參數(shù)也需要傳入這個元素诡渴。很明顯,這樣的方式只是轉(zhuǎn)移了雜亂的代碼菲语,并沒有簡化妄辩,后期頁面修改時帶來的問題也是災(zāi)難性的。
當然山上,我們可以把組件的創(chuàng)建和一些設(shè)置
寫到一個方法去代替寫在{}
前的創(chuàng)建和{}
中的屬性設(shè)置眼耀,比如:
UIView *bgView = [self createBgView];
{
[self.view addSubview:bgView];
// 這里添加子組件
[bgView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(0);
make.size.mas_equalTo(CGSizeMake(200, 200));
}];
}
在createBgView
這個方法中進行創(chuàng)建,設(shè)置屬性等操作佩憾。這樣的寫法其實對于通用的View創(chuàng)建才有用哮伟,如果定制的比較多干花,那么這樣的做法也只是增加了麻煩(因為每一個定制的都需要這樣一個方法),反而得不償失澈吨。
3.其他的優(yōu)化方法
如果可能的話把敢,其實還是更推薦使用storyboard / xib
的布局方式,固定的直接布局谅辣,動態(tài)顯示內(nèi)容用一個父控件去占位修赞,只把動態(tài)的部分去代碼構(gòu)建。畢竟GUI的所帶來的效率提升是顯而易見的桑阶。