天天看點

iOS —— Masonry的Autolayout

頁面布局純寫代碼的三個時期 

MagicNumber -> autoresizingMask -> autolayout

Masonry是一個輕量級的布局架構,擁有自己的描述文法,采用更優雅的鍊式文法封裝自動布局,簡潔明了,并具有高可讀性,而且同時支援 iOS 和 Max OS X。 

AutoLayout和Autoresizing Mask的差別  

•在iOS6之前,關于螢幕旋轉的适配和iPhone,iPad螢幕的自動适配,基本都是由Autoresizing Mask來完成的。但是随着大家對iOS App的要求越來越高,以及今後可能出現的多種螢幕和分辨率的裝置,Autoresizing Mask顯得有些落伍和遲鈍了。AutoLayout可以完成所有原來Autoresizing Mask能完成的工作,同時還能勝任一些原來無法完成的任務,其中包括:

•AutoLayout可以指定任意兩個view的相對位置,而不需要像Autoresizing Mask那樣需要兩個view在直系的view hierarchy中

•AutoLayout不必須指定相等關系的限制,它可以指定非相等限制(大于或者小于等);而Autoresizing Mask所能做的布局隻能是相等條件的

•AutoLayout可以指定限制的優先級,計算frame時将優先按照滿足優先級高的條件進行計算

官方的sample code下Masonry 

[view1 mas_makeConstraints:^(MASConstraintMaker *make) { 

make.edges.equalTo(superview).with.insets(padding); 

}];

Masonry支援的屬性 

@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的對照表 

iOS —— Masonry的Autolayout

其中leading與left trailing與right 在正常情況下是等價的,但是當一些布局是從右至左時(比如阿拉伯文?沒有類似的經驗) 則會對調,換句話說就是基本可以不理不用,用left和right就好了 。

在ios8釋出後,又新增了一堆奇奇怪怪的屬性(有興趣的朋友可以去瞅瞅), Masonry暫時還不支援(不過你要支援ios6,ios7 就沒必要去管那麼多了) 。

MACRO 

#define WS(weakSelf) __weak __typeof(&*self)weakSelf = self;

superView都是一個size為(300,300)的UIView) 

1.居中顯示一個view 

- (void)viewDidLoad { 

[super viewDidLoad]; 

WS(ws); 
UIView *sv = [UIView new]; 
[sv showPlaceHolder]; 
sv.backgroundColor = [UIColor blackColor]; 
[self.view addSubview:sv]; 
[sv mas_makeConstraints:^(MASConstraintMaker *make) { 
make.center.equalTo(ws.view); 
make.size.mas_equalTo(CGSizeMake(320, 320)); 
}]; 
}
iOS —— Masonry的Autolayout

Masonry中添加autolayout限制有三個函數:

- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *make))block; 

- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *make))block; 

- (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))block; 

其 equalTo 和 mas_equalTo的差別: mas_equalTo是一個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隻是對其參數進行了BOX操作(裝箱) MASBoxValue的定義具體可以看看源代碼

所支援的類型 除了NSNumber支援的那些數值類型之外 就隻支援CGPoint CGSize UIEdgeInsets 

2.view略小于其superView

UIView *sv1 = [UIView new]; 

[sv1 showPlaceHolder]; 

sv1.backgroundColor = [UIColor redColor]; 

[sv addSubview:sv1]; 

[sv1 mas_makeConstraints:^(MASConstraintMaker *make) { 

make.edges.equalTo(sv).with.insets(UIEdgeInsetsMake(10, 10, 10, 10)); 

}];

iOS —— Masonry的Autolayout

可以看到 edges 其實就是top,left,bottom,right的一個簡化 分開寫也可以 一句話更省事 

那麼為什麼bottom和right裡的offset是負數呢? 因為這裡計算的是絕對的數值 計算的bottom需要小魚sv的底部高度 是以要-10 同理用于right 

這裡有意思的地方是and和with 其實這兩個函數什麼事情都沒做 

- (MASConstraint *)with { 

return self; 

- (MASConstraint *)and { 

return self; 

}

3.  兩個高度為150的view垂直居中且等寬且等間隔排列 間隔為10(自動計算其寬度) 

int padding1 = 10; 

[sv2 mas_makeConstraints:^(MASConstraintMaker *make) { 

make.centerY.mas_equalTo(sv.mas_centerY); 

make.left.equalTo(sv.mas_left).with.offset(padding1); 

make.right.equalTo(sv3.mas_left).with.offset(-padding1); 

make.height.mas_equalTo(@150); 

make.width.equalTo(sv3); 

}]; 

[sv3 mas_makeConstraints:^(MASConstraintMaker *make) { 

make.centerY.mas_equalTo(sv.mas_centerY); 

make.left.equalTo(sv2.mas_right).with.offset(padding1); 

make.right.equalTo(sv.mas_right).with.offset(-padding1); 

make.height.mas_equalTo(@150); 

make.width.equalTo(sv2); 

}];

iOS —— Masonry的Autolayout

4. UIScrollView順序排列一些view并自動計算contentSize 

UIScrollView *scrollView = [UIScrollView new]; 

scrollView.backgroundColor = [UIColor whiteColor]; 

[sv addSubview:scrollView]; 

[scrollView mas_makeConstraints:^(MASConstraintMaker *make) { 

make.edges.equalTo(sv).with.insets(UIEdgeInsetsMake(5,5,5,5)); 

}]; 

UIView *container = [UIView new]; 

[scrollView addSubview:container]; 

[container mas_makeConstraints:^(MASConstraintMaker *make) { 

make.edges.equalTo(scrollView); 

make.width.equalTo(scrollView); 

}]; 

int count = 10; 

UIView *lastView = nil; 

for ( int i = 1 ; i <= count ; ++i ) 

UIView *subv = [UIView new]; 

[container addSubview:subv]; 

subv.backgroundColor = [UIColor colorWithHue:( arc4random() % 256 / 256.0 ) 

saturation:( arc4random() % 128 / 256.0 ) + 0.5 

brightness:( arc4random() % 128 / 256.0 ) + 0.5 

alpha:1]; 

[subv mas_makeConstraints:^(MASConstraintMaker *make) { 

make.left.and.right.equalTo(container); 

make.height.mas_equalTo(@(20*i)); 

if ( lastView )  { 

make.top.mas_equalTo(lastView.mas_bottom); 

}  else  { 

make.top.mas_equalTo(container.mas_top); 

}]; 

lastView = subv; 

[container mas_makeConstraints:^(MASConstraintMaker *make) { 

make.bottom.equalTo(lastView.mas_bottom); 

}];

頭部

iOS —— Masonry的Autolayout

尾部

iOS —— Masonry的Autolayout

這裡的關鍵就在于container這個view起到了一個中間層的作用 能夠自動的計算uiscrollView的contentSize 

5. 橫向或者縱向等間隙的排列一組view 

很遺憾 autoLayout并沒有直接提供等間隙排列的方法(Masonry的官方demo中也沒有對應的案例)

@implementation UIView(Masonry_LJC) 

- (void) distributeSpacingHorizontallyWith:(NSArray*)views 

NSMutableArray *spaces = [NSMutableArray arrayWithCapacity:views.count+1]; 

for ( int i = 0 ; i < views.count+1 ; ++i ) 

UIView *v = [UIView new]; 

[spaces addObject:v]; 

[self addSubview:v]; 

[v mas_makeConstraints:^(MASConstraintMaker *make) { 

make.width.equalTo(v.mas_height); 

}]; 

UIView *v0 = spaces[0]; 

__weak __typeof(&*self)ws = self; 

[v0 mas_makeConstraints:^(MASConstraintMaker *make) { 

make.left.equalTo(ws.mas_left); 

make.centerY.equalTo(((UIView*)views[0]).mas_centerY); 

}]; 

UIView *lastSpace = v0; 

for ( int i = 0 ; i < views.count; ++i ) 

UIView *obj = views[i]; 

UIView *space = spaces[i+1]; 

[obj mas_makeConstraints:^(MASConstraintMaker *make) { 

make.left.equalTo(lastSpace.mas_right); 

}]; 

[space mas_makeConstraints:^(MASConstraintMaker *make) { 

make.left.equalTo(obj.mas_right); 

make.centerY.equalTo(obj.mas_centerY); 

make.width.equalTo(v0); 

}]; 

lastSpace = space; 

[lastSpace mas_makeConstraints:^(MASConstraintMaker *make) { 

make.right.equalTo(ws.mas_right); 

}]; 

- (void) distributeSpacingVerticallyWith:(NSArray*)views 

NSMutableArray *spaces = [NSMutableArray arrayWithCapacity:views.count+1]; 

for ( int i = 0 ; i < views.count+1 ; ++i ) 

UIView *v = [UIView new]; 

[spaces addObject:v]; 

[self addSubview:v]; 

[v mas_makeConstraints:^(MASConstraintMaker *make) { 

make.width.equalTo(v.mas_height); 

}]; 

UIView *v0 = spaces[0]; 

__weak __typeof(&*self)ws = self; 

[v0 mas_makeConstraints:^(MASConstraintMaker *make) { 

make.top.equalTo(ws.mas_top); 

make.centerX.equalTo(((UIView*)views[0]).mas_centerX); 

}]; 

UIView *lastSpace = v0; 

for ( int i = 0 ; i < views.count; ++i ) 

UIView *obj = views[i]; 

UIView *space = spaces[i+1]; 

[obj mas_makeConstraints:^(MASConstraintMaker *make) { 

make.top.equalTo(lastSpace.mas_bottom); 

}]; 

[space mas_makeConstraints:^(MASConstraintMaker *make) { 

make.top.equalTo(obj.mas_bottom); 

make.centerX.equalTo(obj.mas_centerX); 

make.height.equalTo(v0); 

}]; 

lastSpace = space; 

[lastSpace mas_makeConstraints:^(MASConstraintMaker *make) { 

make.bottom.equalTo(ws.mas_bottom); 

}]; 

@end

簡單的來測試一下

UIView *sv11 = [UIView new]; 

UIView *sv12 = [UIView new]; 

UIView *sv13 = [UIView new]; 

UIView *sv21 = [UIView new]; 

UIView *sv31 = [UIView new]; 

sv11.backgroundColor = [UIColor redColor]; 

sv12.backgroundColor = [UIColor redColor]; 

sv13.backgroundColor = [UIColor redColor]; 

sv21.backgroundColor = [UIColor redColor]; 

sv31.backgroundColor = [UIColor redColor]; 

[sv addSubview:sv11]; 

[sv addSubview:sv12]; 

[sv addSubview:sv13]; 

[sv addSubview:sv21]; 

[sv addSubview:sv31]; 

//給予不同的大小 測試效果 

[sv11 mas_makeConstraints:^(MASConstraintMaker *make) { 

make.centerY.equalTo(@[sv12,sv13]); 

make.centerX.equalTo(@[sv21,sv31]); 

make.size.mas_equalTo(CGSizeMake(40, 40)); 

}]; 

[sv12 mas_makeConstraints:^(MASConstraintMaker *make) { 

make.size.mas_equalTo(CGSizeMake(70, 20)); 

}]; 

[sv13 mas_makeConstraints:^(MASConstraintMaker *make) { 

make.size.mas_equalTo(CGSizeMake(50, 50)); 

}]; 

[sv21 mas_makeConstraints:^(MASConstraintMaker *make) { 

make.size.mas_equalTo(CGSizeMake(50, 20)); 

}]; 

[sv31 mas_makeConstraints:^(MASConstraintMaker *make) { 

make.size.mas_equalTo(CGSizeMake(40, 60)); 

}]; 

[sv distributeSpacingHorizontallyWith:@[sv11,sv12,sv13]]; 

[sv distributeSpacingVerticallyWith:@[sv11,sv21,sv31]]; 

[sv showPlaceHolderWithAllSubviews]; 

[sv hidePlaceHolder];

效果 

iOS —— Masonry的Autolayout

技巧就是使用空白的占位view來填充我們目标view的旁邊這點通過圖上的空白标注可以看出來 。

覺得意猶未盡呢,請下載下傳官方的demo學習。

(來自:裡脊串)

繼續閱讀