天天看点

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学习。

(来自:里脊串)

继续阅读