- Masonry 奕锌、 AutoLayout 、 約束 、 三方庫 阿蝶、 iOS
MagicNumber -> autoresizingMask -> autolayout
以上是純手寫代碼所經(jīng)歷的關(guān)于頁面布局的三個(gè)時(shí)期在iphone1-iphone3gs時(shí)代:window的size固定為(320,480) 。只需要簡(jiǎn)單計(jì)算一下相對(duì)位置就好了黄绩;
在iphone4-iphone4s時(shí)代:蘋果推出了retina屏 但是給了碼農(nóng)們非常大的福利:window的size不變羡洁;
在iphone5-iphone5s時(shí)代:window的size變了(320,568) 這時(shí)autoresizingMask派上了用場(chǎng)(為啥這時(shí)候不用Autolayout? 因?yàn)檫€要支持ios5唄) 簡(jiǎn)單的適配一下即可。
在iphone6+時(shí)代 window的width也發(fā)生了變化(相對(duì)5和5s的屏幕比例沒有變化) 終于是時(shí)候拋棄autoresizingMask改用autolayout了(不用支持ios5了 相對(duì)于屏幕適配的多樣性來說autoresizingMask也已經(jīng)過時(shí)了)
AutoLayout關(guān)于更新的幾個(gè)方法的區(qū)別:
- setNeedsLayout:告知頁面需要更新爽丹,但是不會(huì)立刻開始更新筑煮。執(zhí)行后會(huì)立刻調(diào)用layoutSubviews。
- layoutIfNeeded:告知頁面布局立刻更新粤蝎。所以一般都會(huì)和 setNeedsLayout一起使用真仲。如果希望立刻生成新的frame需要調(diào)用此方法,利用這點(diǎn)一般布局動(dòng)畫可以在更新布局后直接使用這個(gè)方法讓動(dòng)畫生效诽里。
- layoutSubviews:系統(tǒng)重寫布局
- setNeedsUpdateConstraints:告知需要更新約束袒餐,但是不會(huì)立刻開始
- updateConstraintsIfNeeded:告知立刻更新約束
- updateConstraints:系統(tǒng)更新約束
系統(tǒng)約束 |
---|
如果使用系統(tǒng)的約束,大致造型如下:
//創(chuàng)建一個(gè)圖片視圖
UIImageView* imgV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Oggi.png"]];
//圖片為多個(gè)狗狗 合成的不規(guī)則圖片(不規(guī)矩:非圓形谤狡、非矩形????)
imgV.backgroundColor = [UIColor redColor];//可見到背景色
imgV.translatesAutoresizingMaskIntoConstraints = NO;
imgV.contentMode = UIViewContentModeScaleAspectFit;
[self.view addSubview:imgV];
//imgV左側(cè)與父視圖左側(cè) 多出10個(gè)PX
NSLayoutConstraint* leftConstraint = [NSLayoutConstraint constraintWithItem:imgV attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0f constant:10.0f];
//imgV右側(cè)與父視圖右側(cè)對(duì)齊
NSLayoutConstraint* rightConstraint = [NSLayoutConstraint constraintWithItem:imgV attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:0.0f];
//imgV頂部與父視圖頂部 多出20個(gè)PX
NSLayoutConstraint* topConstraint = [NSLayoutConstraint constraintWithItem:imgV attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:20.0f];
//imgV高度為父視圖高度一半
NSLayoutConstraint* heightConstraint = [NSLayoutConstraint constraintWithItem:imgV attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:0.5f constant:0.0f];
//iOS 6.0或者7.0調(diào)用addConstraints
//[self.view addConstraints:@[leftConstraint, rightConstraint, topConstraint, heightConstraint]];
//iOS 8.0以后設(shè)置active屬性值
leftConstraint.active = YES;
rightConstraint.active = YES;
topConstraint.active = YES;
heightConstraint.active = YES;
屬性過多灸眼,代碼冗余繁雜!D苟焰宣!
反正我是不想用。
Xib 或者 StoryBoard </br> ??lazy but so convenient |
---|
那么還有一個(gè)最懶的方法捕仔,xib和storyBoard拖以及設(shè)置約束匕积。但是維護(hù)起來很繁雜。牽一發(fā)而動(dòng)全身榜跌。(一點(diǎn)小失誤幾乎就得重頭再來闪唆。。钓葫。????)
作為一名Coder悄蕾,還是多敲敲代碼吧!享受指尖上的??础浮!????
三方庫Masonry |
---|
主角 Masonry登場(chǎng)了
Masonry是一個(gè)基于AutoLayout框架的輕量級(jí)布局框架帆调。比系統(tǒng)自帶
Masonry 源碼:https://github.com/Masonry/Masonry
Masonry支持的一些屬性:
make是MASConstraintMaker類型。MASConstraintMaker給我們提供了22種Attribute類型
//Basic Attribute
@property (nonatomic, strong, readonly) MASConstraint *left;
@property (nonatomic, strong, readonly) MASConstraint *top;
@property (nonatomic, strong, readonly) MASConstraint *right;
@property (nonatomic, strong, readonly) MASConstraint *bottom;
@property (nonatomic, strong, readonly) MASConstraint *leading;
@property (nonatomic, strong, readonly) MASConstraint *trailing;
@property (nonatomic, strong, readonly) MASConstraint *width;
@property (nonatomic, strong, readonly) MASConstraint *height;
@property (nonatomic, strong, readonly) MASConstraint *centerX;
@property (nonatomic, strong, readonly) MASConstraint *centerY;
@property (nonatomic, strong, readonly) MASConstraint *baseline;
這些屬性與NSLayoutAttrubute的對(duì)照表如下:
//Margin Attribute
@property (nonatomic, strong, readonly) MASConstraint *leftMargin;
@property (nonatomic, strong, readonly) MASConstraint *rightMargin;
@property (nonatomic, strong, readonly) MASConstraint *topMargin;
@property (nonatomic, strong, readonly) MASConstraint *bottomMargin;
@property (nonatomic, strong, readonly) MASConstraint *leadingMargin;
@property (nonatomic, strong, readonly) MASConstraint *trailingMargin;
@property (nonatomic, strong, readonly) MASConstraint *centerXWithinMargins;
@property (nonatomic, strong, readonly) MASConstraint *centerYWithinMargins;
//Convenient Attribute
@property (nonatomic, strong, readonly) MASConstraint *edges;
@property (nonatomic, strong, readonly) MASConstraint *size;
@property (nonatomic, strong, readonly) MASConstraint *center;
更多細(xì)節(jié)豆同,參考:第三方 Masonry約束的使用
這里就不使用下載三方庫番刊,拖入工程的方式導(dǎo)入了。使用cocoapods在終端里導(dǎo)入Masonry 影锈。( 記住vim Podlife前,先pod init創(chuàng)建pod文件 本人精彩犯錯(cuò)?? ?? ?? )
platform :ios, '9.0'
pod 'Masonry' '~> 1.4' #'~> 1.4'版本號(hào) 根據(jù)需求可要可不要
然后按Esc,并且輸入“ :”號(hào)進(jìn)入vim命令模式锄禽,然后在冒號(hào)后邊輸入wq
導(dǎo)入成功后即可使用Masonry約束進(jìn)行布局潜必。
先介紹一個(gè)MACRO (因?yàn)槭褂昧薆lock,需要弱引用)
#define WS(weakSelf) __weak __typeof(&*self)weakSelf = self;
首先在Masonry中能夠添加autolayout約束有三個(gè)函數(shù)
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *make))block;
- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *make))block;
- (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))block;
/*
mas_makeConstraints 只負(fù)責(zé)新增約束 Autolayout不能同時(shí)存在 兩條針對(duì)于 同一對(duì)象 的約束 否則會(huì)報(bào)錯(cuò)
mas_updateConstraints 針對(duì)上面的情況 會(huì) 更新 在block中出現(xiàn)的約束 不會(huì)導(dǎo)致出現(xiàn)兩個(gè)相同約束的情況
mas_remakeConstraints 則會(huì) 清除 之前的 所有約束 僅保留最新的約束
三種函數(shù)善加利用 就可以應(yīng)對(duì)各種情況了
*/
其次 equalTo 和 mas_equalTo的區(qū)別在哪里呢? 其實(shí) mas_equalTo是一個(gè)MACRO
#define mas_equalTo(...) equalTo(MASBoxValue((__VA_ARGS__)))
#define mas_greaterThanOrEqualTo(...) greaterThanOrEqualTo(MASBoxValue((__VA_ARGS__)))
#define mas_lessThanOrEqualTo(...) lessThanOrEqualTo(MASBoxValue((__VA_ARGS__)))
#define mas_offset(...) valueOffset(MASBoxValue((__VA_ARGS__)))
可以看到 mas_equalTo只是對(duì)其參數(shù)進(jìn)行了一個(gè)BOX操作(裝箱) 類似于宏
MASBoxValue的定義具體可看看其源代碼
所支持的類型 除了NSNumber支持的那些數(shù)值類型之外
就只支持CGPoint CGSize UIEdgeInsets
equalTo()
的括號(hào)里放:視圖沃但、mas_width
等屬性磁滚、@100
(對(duì)象);
mas_equalTo()
的括號(hào)里放:float
(基本數(shù)據(jù)類型)宵晚。
首先導(dǎo)入庫頭文件
#import <Masonry.h>
再寫一些后面需要的常用定義宏
#define WS(weakSelf) __weak __typeof(&*self)weakSelf = self; //block弱引用
#define screen_W [UIScreen mainScreen].bounds.size.width //屏寬
#define screen_H [UIScreen mainScreen].bounds.size.height //屏高
NSMutableArray * imgV_Arr = @[].mutableCopy;
for (int i = 0; i < 10; i ++) { //構(gòu)建10個(gè)圖片試圖
UIImageView * imgV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Oggi.png"]];
imgV.backgroundColor = [UIColor colorWithRed:arc4random()%256/255.f green:arc4random()%256/255.f blue:arc4random()%256/255.f alpha:1];
//隨機(jī)色生成
[imgV_Arr addObject:imgV];//數(shù)組 添加圖片
[self.view addSubview:imgV];
imgV.frame = CGRectMake(i*screen_W/5.f, 0, screen_W/5.f, screen_H/10.f);
}
WS(ws); //弱引用 __block修飾
[imgV_Arr[5] mas_makeConstraints:^(MASConstraintMaker *make) { //第6張圖片處理
make.center.equalTo(ws.view); //中心 對(duì)齊
make.size.mas_equalTo(CGSizeMake(260, 160));//尺寸
}];
[imgV_Arr[6] mas_makeConstraints:^(MASConstraintMaker *make) { //第7張圖片處理
make.edges.equalTo(imgV_Arr[5]).with.insets(UIEdgeInsetsMake(20, 20, 20, 20)); // 包含在內(nèi)部 內(nèi)嵌
/* 等價(jià)于 */
// make.top.equalTo(imgV_Arr[5]).with.offset(20);
// make.left.equalTo(imgV_Arr[5]).with.offset(20);
// make.bottom.equalTo(imgV_Arr[5]).with.offset(-20);
// make.right.equalTo(imgV_Arr[5]).with.offset(-20);
/* 也等價(jià)于 */
// make.top.left.bottom.and.right.equalTo(imgV_Arr[5]).with.insets(UIEdgeInsetsMake(20, 20, 20, 20));
}];
UIView * backView = [UIView new];//純色 背景視圖
backView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:backView];
[backView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(ws.view).with.offset(30);
make.bottom.equalTo(ws.view).with.offset(-10);
make.right.equalTo(ws.view).with.offset(-50);
make.size.mas_equalTo(CGSizeMake(screen_W, screen_H/3.f));
}];
UIImageView * imgV7 = imgV_Arr[7];//第8張圖片處理
UIImageView * imgV8 = imgV_Arr[8]; //第9張圖片處理
UIImageView * imgV9 = imgV_Arr[9];//第10張圖片處理
//轉(zhuǎn)換為 視圖格式(?? 才對(duì)應(yīng).mas_left垂攘、.mas_right屬性 ??)
[backView addSubview: imgV7];
[backView addSubview: imgV8];
[backView addSubview:imgV9];
int padding = 10; //左右間距
[imgV7 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(backView.mas_centerY);
make.left.equalTo(backView.mas_left).with.offset(padding);
make.right.equalTo(imgV8.mas_left).with.offset(-padding);
make.height.mas_equalTo(@100);//NSNumber類型
make.width.equalTo(imgV8);
}];
[imgV8 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(backView.mas_centerY);
make.left.equalTo(imgV7.mas_right).with.offset(padding);
make.right.equalTo(backView.mas_right).with.offset(-padding);
make.height.mas_equalTo(backView.mas_height);
make.width.equalTo(imgV7);
}];
// 動(dòng)畫
[imgV9 mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(backView).offset(30);
make.bottom.equalTo(imgV7.mas_top).offset(-5);
make.width.equalTo(@50);
}];
[UIView animateWithDuration:3 animations:^{ //三秒內(nèi) 播放
[backView layoutIfNeeded];
}];
// 因?yàn)椴季旨s束就是要 脫離frame表達(dá)方式,可是動(dòng)畫是需要根據(jù)這個(gè)來執(zhí)行淤刃,就會(huì)有
矛盾晒他,但根據(jù)前面說到布局約束的原理,在 某個(gè)時(shí)刻 約束也是會(huì)被 還原 成frame使視圖
顯示逸贾,這個(gè)時(shí)刻可通過 layoutIfNeeded這個(gè)方法來進(jìn)行控制陨仅。
效果:
-
因?yàn)椴季旨s束就是要 脫離frame表達(dá)方式,可是動(dòng)畫是需要根據(jù)這個(gè)來執(zhí)行铝侵,就會(huì)有矛盾灼伤,但根據(jù)前面說到布局約束的原理,在 某個(gè)時(shí)刻 約束也是會(huì)被 還原 成frame使視圖顯示咪鲜,這個(gè)時(shí)刻可通過 layoutIfNeeded這個(gè)方法來進(jìn)行控制狐赡。
[UIView animateWithDuration:3 animations:^{ //三秒內(nèi) 播放 [backView layoutIfNeeded]; }];
后續(xù)有時(shí)間繼續(xù)更新!
后續(xù)有時(shí)間繼續(xù)更新疟丙!
后續(xù)有時(shí)間繼續(xù)更新颖侄!
一直說詳細(xì)寫一下“UIScrollView的約束建立”,沒時(shí)間O斫肌览祖!注意的一點(diǎn)就是:UIScrollView的contentSize尺寸大小:
1.若大于里面所有約束好的子控件的整體大小,那么直接顯示完所有的子控件;
2.若大于里面所有約束好的子控件的整體(的寬度爽室、高度)大小帘靡,則在其寬度、高度上面把UIScrollView的contentSize拉伸開來
??以后有空再舉了~??????