目前iOS開發(fā)中大多數(shù)頁面都已經(jīng)開始使用Interface Builder的方式進行UI開發(fā)了,但是在一些變化比較復雜的頁面敷搪,還是需要通過代碼來進行UI開發(fā)的。而且有很多比較老的項目幢哨,本身就還在采用純代碼的方式進行開發(fā)赡勘。
而現(xiàn)在iPhone和iPad屏幕尺寸越來越多,雖然開發(fā)者只需要根據(jù)屏幕點進行開發(fā)捞镰,而不需要基于像素點進行UI開發(fā)闸与。但如果在項目中根據(jù)不同屏幕尺寸進行各種判斷,寫死坐標的話曼振,這樣開發(fā)起來是很吃力的几迄。
所以一般用純代碼開發(fā)UI的話,一般都是配合一些自動化布局的框架進行屏幕適配冰评。蘋果為我們提供的適配框架有:VFL、UIViewAutoresizing木羹、Auto Layout甲雅、Size Classes等。
其中Auto Layout是使用頻率最高的布局框架坑填,但是其也有弊端抛人。就是在使用UILayoutConstraint的時候,會發(fā)現(xiàn)代碼量很多脐瑰,而且大多都是重復性的代碼妖枚,以至于好多人都不想用這個框架。
后來Github上的出現(xiàn)了基于UILayoutConstraint封裝的第三方布局框架Masonry苍在,Masonry使用起來非常方便绝页,本篇文章就詳細講一下Masonry的使用荠商。
Masonry介紹
這篇文章只是簡單介紹Masonry,以及Masonry的使用续誉,并且會舉一些例子出來莱没。但并不會涉及到Masonry的內(nèi)部實現(xiàn),以后會專門寫篇文章來介紹其內(nèi)部實現(xiàn)原理酷鸦,包括順便講一下鏈式語法饰躲。
什么是Masonry
Masonry是一個對系統(tǒng)NSLayoutConstraint進行封裝的第三方自動布局框架,采用鏈式編程的方式提供給開發(fā)者API嘹裂。系統(tǒng)AutoLayout支持的操作焦蘑,Masonry都支持,相比系統(tǒng)API功能來說,Masonry是有過之而無不及宁舰。
Masonry采取了鏈式編程的方式拼卵,代碼理解起來非常清晰易懂,而且寫完之后代碼量看起來非常少即寡。之前用NSLayoutConstraint寫很多代碼才能實現(xiàn)的布局,用Masonry最少一行代碼就可以搞定墩蔓。下面看到Masonry的代碼就會發(fā)現(xiàn),太簡單易懂了。
Masonry是同時支持Mac和iOS兩個平臺的样刷,在這兩個平臺上都可以使用Masonry進行自動布局夫壁。我們可以從MASUtilities.h文件中,看到下面的定義,這就是Masonry通過宏定義的方式肺缕,區(qū)分兩個平臺獨有的一些關(guān)鍵字。
Github地址:https://github.com/SnapKit/Masonry
集成方式
Masonry支持CocoaPods芥映,可以直接通過podfile文件進行集成坞嘀,需要在CocoaPods中添加下面代碼:
1pod?'Masonry'
Masonry學習建議
在UI開發(fā)中,純代碼和Interface
Builder我都是用過的内狸,在開發(fā)過程中也積累了一些經(jīng)驗锰瘸。對于初學者學習純代碼AutoLayout舞萄,我建議還是先學會Interface
Builder方式的AutoLayout,領(lǐng)悟蘋果對自動布局的規(guī)則和思想甘晤,然后再把這套思想嵌套在純代碼上。這樣學習起來更好入手,也可以避免踩好多坑。
在項目中設(shè)置的AutoLayout約束诀黍,起到對視圖布局的標記作用。設(shè)置好約束之后,程序運行過程中創(chuàng)建視圖時,會根據(jù)設(shè)置好的約束計算frame范咨,并渲染到視圖上。
所以在純代碼情況下,視圖設(shè)置的約束是否正確它浅,要以運行之后顯示的結(jié)果和打印的log為準。
Masonry中的坑
在使用Masonry進行約束時,有一些是需要注意的。
在使用Masonry添加約束之前与纽,需要在addSubview之后才能使用蹦肴,否則會導致崩潰勺阐。
在添加約束時初學者經(jīng)常會出現(xiàn)一些錯誤,約束出現(xiàn)問題的原因一般就是兩種:約束沖突和缺少約束。對于這兩種問題,可以通過調(diào)試和log排查玩焰。
之前使用Interface Builder添加約束荔棉,如果約束有錯誤直接就可以看出來羡棵,并且會以紅色或者黃色警告體現(xiàn)出來。而Masonry則不會直觀的體現(xiàn)出來,而是以運行過程中崩潰或者打印異常log體現(xiàn),所以這也是手寫代碼進行AutoLayout的一個缺點嚣伐。
這個問題只能通過多敲代碼逝变,積攢純代碼進行AutoLayout的經(jīng)驗拱层,慢慢就用起來越來越得心應手了悠汽。
Masonry基礎(chǔ)使用
Masonry基礎(chǔ)API
1
2
3
4
5
6
7
8
9
mas_makeConstraints()????添加約束
mas_remakeConstraints()??移除之前的約束茬高,重新添加新的約束
mas_updateConstraints()??更新約束
equalTo()???????參數(shù)是對象類型,一般是視圖對象或者mas_width這樣的坐標系對象
mas_equalTo()???和上面功能相同,參數(shù)可以傳遞基礎(chǔ)數(shù)據(jù)類型對象由桌,可以理解為比上面的API更強大
width()?????????用來表示寬度剪廉,例如代表view的寬度
mas_width()?????用來獲取寬度的值捌斧。和上面的區(qū)別在于爆哑,一個代表某個坐標系對象队贱,一個用來獲取坐標系對象的值
Auto Boxing
上面例如equalTo或者width這樣的屯换,有時候需要涉及到使用mas_前綴,這在開發(fā)中需要注意作區(qū)分抑片。
如果在當前類引入#import "Masonry.h"之前,用下面兩種宏定義聲明一下,就不需要區(qū)分mas_前綴。
1
2
3
4
//?定義這個常量架诞,就可以不用在開發(fā)過程中使用"mas_"前綴很泊。
#define?MAS_SHORTHAND
//?定義這個常量均驶,就可以讓Masonry幫我們自動把基礎(chǔ)數(shù)據(jù)類型的數(shù)據(jù),自動裝箱為對象類型。
#define?MAS_SHORTHAND_GLOBALS
修飾語句
Masonry為了讓代碼使用和閱讀更容易理解,所以直接通過點語法就可以調(diào)用虏两,還添加了and和with兩個方法搁廓。這兩個方法內(nèi)部實際上什么都沒干凌停,只是在內(nèi)部將self直接返回完箩,功能就是為了更加方便閱讀,對代碼執(zhí)行沒有實際作用。
例如下面的例子:
1make.top.and.bottom.equalTo(self.containerView).with.offset(padding);
其內(nèi)部代碼實現(xiàn),實際上就是直接將self返回。
1
2
3
-?(MASConstraint?*)with{
????returnself;
}
更新約束和布局
關(guān)于更新約束布局相關(guān)的API,主要用以下四個API:
1
2
3
4
-?(void)updateConstraintsIfNeeded??調(diào)用此方法,如果有標記為需要重新布局的約束,則立即進行重新布局,內(nèi)部會調(diào)用updateConstraints方法
-?(void)updateConstraints??????????重寫此方法,內(nèi)部實現(xiàn)自定義布局過程
-?(BOOL)needsUpdateConstraints?????當前是否需要重新布局夜郁,內(nèi)部會判斷當前有沒有被標記的約束
-?(void)setNeedsUpdateConstraints??標記需要進行重新布局
關(guān)于UIView重新布局相關(guān)的API庙睡,主要用以下三個API:
1
2
3
-?(void)setNeedsLayout??標記為需要重新布局
-?(void)layoutIfNeeded??查看當前視圖是否被標記需要重新布局,有則在內(nèi)部調(diào)用layoutSubviews方法進行重新布局
-?(void)layoutSubviews??重寫當前方法谣拣,在內(nèi)部完成重新布局操作
Masonry示例代碼
Masonry本質(zhì)上就是對系統(tǒng)AutoLayout進行的封裝,包括里面很多的API,都是對系統(tǒng)API進行了一次二次包裝拴还。
1
2
3
4
5
6
7
8
9
10
11
12
13
typedef?NS_OPTIONS(NSInteger,?MASAttribute)?{
????MASAttributeLeft?=?1?<<?NSLayoutAttributeLeft,
????MASAttributeRight?=?1?<<?NSLayoutAttributeRight,
????MASAttributeTop?=?1?<<?NSLayoutAttributeTop,
????MASAttributeBottom?=?1?<<?NSLayoutAttributeBottom,
????MASAttributeLeading?=?1?<<?NSLayoutAttributeLeading,
????MASAttributeTrailing?=?1?<<?NSLayoutAttributeTrailing,
????MASAttributeWidth?=?1?<<?NSLayoutAttributeWidth,
????MASAttributeHeight?=?1?<<?NSLayoutAttributeHeight,
????MASAttributeCenterX?=?1?<<?NSLayoutAttributeCenterX,
????MASAttributeCenterY?=?1?<<?NSLayoutAttributeCenterY,
????MASAttributeBaseline?=?1?<<?NSLayoutAttributeBaseline,
};
常用方法
設(shè)置內(nèi)邊距
1
2
3
4
5
6
7
8
9
10
11
12
13
/**?
?設(shè)置yellow視圖和self.view等大费封,并且有10的內(nèi)邊距焚鹊。
?注意根據(jù)UIView的坐標系,下面right和bottom進行了取反韧献。所以不能寫成下面這樣末患,否則right研叫、bottom這兩個方向會出現(xiàn)問題阻塑。
?make.edges.equalTo(self.view).with.offset(10);
?除了下面例子中的offset()方法蓝撇,還有針對不同坐標系的centerOffset()、sizeOffset()陈莽、valueOffset()之類的方法渤昌。
?*/
[self.yellowView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.left.equalTo(self.view).with.offset(10);
????make.top.equalTo(self.view).with.offset(10);
????make.right.equalTo(self.view).with.offset(-10);
????make.bottom.equalTo(self.view).with.offset(-10);
}];
通過insets簡化設(shè)置內(nèi)邊距的方式
1
2
3
4
5
//?下面的方法和上面例子等價,區(qū)別在于使用insets()方法走搁。
[self.blueView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????//?下独柑、右不需要寫負號,insets方法中已經(jīng)為我們做了取反的操作了私植。
????make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(10,?10,?10,?10));
}];
更新約束
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//?設(shè)置greenView的center和size忌栅,這樣就可以達到簡單進行約束的目的
[self.greenView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.center.equalTo(self.view);
????//?這里通過mas_equalTo給size設(shè)置了基礎(chǔ)數(shù)據(jù)類型的參數(shù),參數(shù)為CGSize的結(jié)構(gòu)體
????make.size.mas_equalTo(CGSizeMake(300,?300));
}];
//?為了更清楚的看出約束變化的效果曲稼,在顯示兩秒后更新約束索绪。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,?(int64_t)(2.f?*?NSEC_PER_SEC)),?dispatch_get_main_queue(),?^{
????[self.greenView?mas_updateConstraints:^(MASConstraintMaker?*make)?{
????????make.centerX.equalTo(self.view).offset(100);
????????make.size.mas_equalTo(CGSizeMake(100,?100));
????}];
});
大于等于和小于等于某個值的約束
1
2
3
4
5
6
7
[self.textLabel?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.center.equalTo(self.view);
????//?設(shè)置寬度小于等于200
????make.width.lessThanOrEqualTo(@200);
????//?設(shè)置高度大于等于10
????make.height.greaterThanOrEqualTo(@(10));
}];
self.textLabel.text
=
@"這是測試的字符串。能看到1贫悄、2瑞驱、3個步驟,第一步當然是上傳照片了窄坦,要上傳正面近照哦唤反。上傳后,網(wǎng)站會自動識別你的面部鸭津,如果覺得識別的不準彤侍,你還可以手動修改一下。左邊可以看到16項修改參數(shù)逆趋,最上面是整體修改盏阶,你也可以根據(jù)自己的意愿單獨修改某項,將鼠標放到選項上面父泳,右邊的預覽圖會顯示相應的位置般哼。";
textLabel只需要設(shè)置一個屬性即可
1self.textLabel.numberOfLines?=?0;
使用基礎(chǔ)數(shù)據(jù)類型當做參數(shù)
1
2
3
4
5
6
7
8
9
10
11
12
/**?
?如果想使用基礎(chǔ)數(shù)據(jù)類型當做參數(shù),Masonry為我們提供了"mas_xx"格式的宏定義惠窄。
?這些宏定義會將傳入的基礎(chǔ)數(shù)據(jù)類型轉(zhuǎn)換為NSNumber類型蒸眠,這個過程叫做封箱(Auto?Boxing)。
?"mas_xx"開頭的宏定義杆融,內(nèi)部都是通過MASBoxValue()函數(shù)實現(xiàn)的楞卡。
?這樣的宏定義主要有四個,分別是mas_equalTo()、mas_offset()和大于等于蒋腮、小于等于四個淘捡。
?*/
[self.redView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.center.equalTo(self.view);
????make.width.mas_equalTo(100);
????make.height.mas_equalTo(100);
}];
設(shè)置約束優(yōu)先級
1
2
3
4
5
6
7
8
9
10
11
/**?
?Masonry為我們提供了三個默認的方法,priorityLow()池摧、priorityMedium()焦除、priorityHigh(),這三個方法內(nèi)部對應著不同的默認優(yōu)先級作彤。
?除了這三個方法膘魄,我們也可以自己設(shè)置優(yōu)先級的值,可以通過priority()方法來設(shè)置竭讳。
?*/
[self.redView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.center.equalTo(self.view);
????make.width.equalTo(self.view).priorityLow();
????make.width.mas_equalTo(20).priorityHigh();
????make.height.equalTo(self.view).priority(200);
????make.height.mas_equalTo(100).priority(1000);
}];
1
2
3
4
5
6
Masonry也幫我們定義好了一些默認的優(yōu)先級常量创葡,分別對應著不同的數(shù)值,優(yōu)先級最大數(shù)值是1000绢慢。
static?const?MASLayoutPriority?MASLayoutPriorityRequired?=?UILayoutPriorityRequired;
static?const?MASLayoutPriority?MASLayoutPriorityDefaultHigh?=?UILayoutPriorityDefaultHigh;
static?const?MASLayoutPriority?MASLayoutPriorityDefaultMedium?=?500;
static?const?MASLayoutPriority?MASLayoutPriorityDefaultLow?=?UILayoutPriorityDefaultLow;
static?const?MASLayoutPriority?MASLayoutPriorityFittingSizeLevel?=?UILayoutPriorityFittingSizeLevel;
設(shè)置約束比例
1
2
3
4
5
6
//?設(shè)置當前約束值乘以多少灿渴,例如這個例子是redView的寬度是self.view寬度的0.2倍。
[self.redView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.center.equalTo(self.view);
????make.height.mas_equalTo(30);
????make.width.equalTo(self.view).multipliedBy(0.2);
}];
小練習
子視圖等高練習
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**?
?下面的例子是通過給equalTo()方法傳入一個數(shù)組胰舆,設(shè)置數(shù)組中子視圖及當前make對應的視圖之間等高骚露。
?需要注意的是,下面block中設(shè)置邊距的時候缚窿,應該用insets來設(shè)置荸百,而不是用offset。
?因為用offset設(shè)置right和bottom的邊距時滨攻,這兩個值應該是負數(shù),所以如果通過offset來統(tǒng)一設(shè)置值會有問題蓝翰。
?*/
CGFloat?padding?=?LXZViewPadding;
[self.redView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.left.right.top.equalTo(self.view).insets(UIEdgeInsetsMake(padding,?padding,?0,?padding));
????make.bottom.equalTo(self.blueView.mas_top).offset(-padding);
}];
[self.blueView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.left.right.equalTo(self.view).insets(UIEdgeInsetsMake(0,?padding,?0,?padding));
????make.bottom.equalTo(self.yellowView.mas_top).offset(-padding);
}];
/**?
?下面設(shè)置make.height的數(shù)組是關(guān)鍵光绕,通過這個數(shù)組可以設(shè)置這三個視圖高度相等。其他例如寬度之類的畜份,也是類似的方式诞帐。
?*/
[self.yellowView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.left.right.bottom.equalTo(self.view).insets(UIEdgeInsetsMake(0,?padding,?padding,?padding));
????make.height.equalTo(@[self.blueView,?self.redView]);
}];
子視圖垂直居中練習
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**?
?要求:(這個例子是在其他人博客里看到的,然后按照要求自己寫了下面這段代碼)
?兩個視圖相對于父視圖垂直居中爆雹,并且兩個視圖以及父視圖之間的邊距均為10停蕉,高度為150,兩個視圖寬度相等钙态。
?*/
CGFloat?padding?=?10.f;
[self.blueView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.centerY.equalTo(self.view);
????make.left.equalTo(self.view).mas_offset(padding);
????make.right.equalTo(self.redView.mas_left).mas_offset(-padding);
????make.width.equalTo(self.redView);
????make.height.mas_equalTo(150);
}];
[self.redView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.centerY.equalTo(self.view);
????make.right.equalTo(self.view).mas_offset(-padding);
????make.width.equalTo(self.blueView);
????make.height.mas_equalTo(150);
}];
UITableView動態(tài)Cell高度
在iOS UI開發(fā)過程中慧起,UITableView的動態(tài)Cell高度一直都是個問題。實現(xiàn)這樣的需求册倒,實現(xiàn)方式有很多種蚓挤,只是實現(xiàn)起來復雜程度和性能的區(qū)別。
在不考慮性能的情況下,tableView動態(tài)Cell高度灿意,可以采取估算高度的方式估灿。如果通過估算高度的方式實現(xiàn)的話,無論是純代碼還是Interface Builder缤剧,都只需要兩行代碼就可以完成Cell自動高度適配馅袁。
實現(xiàn)方式:
需要設(shè)置tableView的rowHeight屬性,這里設(shè)置為自動高度荒辕,告訴系統(tǒng)Cell的高度是不固定的汗销,需要系統(tǒng)幫我們進行計算。然后設(shè)置tableView的estimatedRowHeight屬性兄纺,設(shè)置一個估計的高度大溜。(我這里用的代理方法,實際上都一樣)
原理:
這樣的話估脆,在tableView被創(chuàng)建之后钦奋,系統(tǒng)會根據(jù)estimatedRowHeight屬性設(shè)置的值,為tableView設(shè)置一個估計的值疙赠。然后在Cell顯示的時候再獲取Cell的高度付材,并刷新tableView的contentSize。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
-?(void)tableViewConstraints?{
????[self.tableView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????????make.edges.equalTo(self.view);
????}];
}
-?(NSInteger)tableView:(UITableView?*)tableView?numberOfRowsInSection:(NSInteger)section?{
????returnself.dataList.count;
}
-?(MasonryTableViewCell?*)tableView:(UITableView?*)tableView?cellForRowAtIndexPath:(NSIndexPath?*)indexPath?{
????MasonryTableViewCell?*cell?=?[tableView?dequeueReusableCellWithIdentifier:LXZTableViewCellIdentifier];
????[cell?reloadViewWithText:self.dataList[indexPath.row]];
????returncell;
}
//?需要注意的是圃阳,這個代理方法和直接返回當前Cell高度的代理方法并不一樣厌衔。
//?這個代理方法會將當前所有Cell的高度都預估出來,而不是只計算顯示的Cell捍岳,所以這種方式對性能消耗還是很大的富寿。
//?所以通過設(shè)置estimatedRowHeight屬性的方式,和這種代理方法的方式锣夹,最后性能消耗都是一樣的页徐。
-?(CGFloat)tableView:(UITableView?*)tableView?estimatedHeightForRowAtIndexPath:(NSIndexPath?*)indexPath?{
????return50.f;
}
-?(UITableView?*)tableView?{
????if(!_tableView)?{
????????_tableView?=?[[UITableView?alloc]?initWithFrame:CGRectZero?style:UITableViewStylePlain];
????????_tableView.delegate?=?self;
????????_tableView.dataSource?=?self;
????????//?設(shè)置tableView自動高度
????????_tableView.rowHeight?=?UITableViewAutomaticDimension;
????????[_tableView?registerClass:[MasonryTableViewCell?class]?forCellReuseIdentifier:LXZTableViewCellIdentifier];
????????[self.view?addSubview:_tableView];
????}
????return_tableView;
}
UIScrollView自動布局
之前聽很多人說過UIScrollView很麻煩疲吸,然而我并沒有感覺到有多麻煩(并非裝逼)弄唧。我感覺說麻煩的人可能根本就沒試過吧注盈,只是覺得很麻煩而已骚灸。
我這里就講一下兩種進行UIScrollView自動布局的方案孵运,并且會講一下自動布局的技巧絮记,只要掌握技巧振乏,布局其實很簡單恰聘。
布局小技巧:
給UIScrollView添加的約束是定義其frame戳气,設(shè)置contentSize是定義其內(nèi)部大小链患。UIScrollView進行addSubview操作,都是將其子視圖添加到contentView上物咳。
所以锣险,添加到UIScrollView上的子視圖蹄皱,對UIScrollView添加的約束都是作用于contentView上的。只需要按照這樣的思路給UIScrollView設(shè)置約束芯肤,就可以掌握設(shè)置約束的技巧了巷折。
提前設(shè)置contentSize
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//?提前設(shè)置好UIScrollView的contentSize,并設(shè)置UIScrollView自身的約束
self.scrollView.contentSize?=?CGSizeMake(1000,?1000);
[self.scrollView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.edges.equalTo(self.view);
}];
//?雖然redView的get方法內(nèi)部已經(jīng)執(zhí)行過addSubview操作崖咨,但是UIView始終以最后一次添加的父視圖為準锻拘,也就是redView始終是在最后一次添加的父視圖上。
[self.scrollView?addSubview:self.redView];
[self.redView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.left.top.equalTo(self.scrollView);
????make.width.height.mas_equalTo(200);
}];
[self.scrollView?addSubview:self.blueView];
[self.blueView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.left.equalTo(self.redView.mas_right);
????make.top.equalTo(self.scrollView);
????make.width.height.equalTo(self.redView);
}];
[self.scrollView?addSubview:self.greenView];
[self.greenView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.left.equalTo(self.scrollView);
????make.top.equalTo(self.redView.mas_bottom);
????make.width.height.equalTo(self.redView);
}];
自動contentSize
上面的例子是提前設(shè)置好UIScrollView的contentSize的內(nèi)部size击蹲,然后直接向里面addSubview署拟。但是這有個要求就是,需要提前知道contentSize的大小歌豺,不然沒法設(shè)置推穷。
這個例子中將會展示動態(tài)改變contentSize的大小,內(nèi)部視圖有多少contentSize就自動擴充到多大类咧。
這種方式的實現(xiàn)馒铃,主要是依賴于創(chuàng)建一個containerView內(nèi)容視圖,并添加到UIScrollView上作為子視圖痕惋。UIScrollView原來的子視圖都添加到containerView上区宇,并且和這個視圖設(shè)置約束。
因為對UIScrollView進行addSubview操作的時候值戳,本質(zhì)上是往其contentView上添加议谷。也就是containerView的父視圖是contentView,通過containerView撐起contentView視圖的大小堕虹,以此來實現(xiàn)動態(tài)改變contentSize卧晓。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//?在進行約束的時候,要對containerView的上下左右都添加和子視圖的約束赴捞,以便確認containerView的邊界區(qū)域禀崖。
[self.scrollView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.edges.equalTo(self.view);
}];
CGFloat?padding?=?LXZViewPadding;
[self.containerView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.edges.equalTo(self.scrollView).insets(UIEdgeInsetsMake(padding,?padding,?padding,?padding));
}];
[self.containerView?addSubview:self.greenView];
[self.greenView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.top.left.equalTo(self.containerView).offset(padding);
????make.size.mas_equalTo(CGSizeMake(250,?250));
}];
[self.containerView?addSubview:self.redView];
[self.redView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.top.equalTo(self.containerView).offset(padding);
????make.left.equalTo(self.greenView.mas_right).offset(padding);
????make.size.equalTo(self.greenView);
????make.right.equalTo(self.containerView).offset(-padding);
}];
[self.containerView?addSubview:self.yellowView];
[self.yellowView?mas_makeConstraints:^(MASConstraintMaker?*make)?{
????make.left.equalTo(self.containerView).offset(padding);
????make.top.equalTo(self.greenView.mas_bottom).offset(padding);
????make.size.equalTo(self.greenView);
????make.bottom.equalTo(self.containerView).offset(-padding);
}];