为什么要做这个笔记
masonry 可以说是当前 iOS
开发中最流行的 Autolayout
框架,其极大的简化了苹果原生提供的AutoLayout
语法。目前很多大厂也是用的这个自动布局框架,我司也在用。在此之前我一只在用另一个叫 SDAutolayout的自动布局库,所以 masonry
是个初学者,如果写得不好的地方还希望大佬指点江山。经过前段时间的开发项目,对masonry
框架有了大致的认识,用法上面基本能解决所有布局问题。
masonry 基础约束用法
- 首先先提及一下,view 在执行 masonry 布局之前必须添加到父视图上
- 约束的写法有好几种,我先拿三种来举例
- 第一种。mas_equalTo()方法传入一个依赖的约束边,如下面示例中“self.view.mas_left”,后面跟着 mas_offset()方法可以传入一个值,这个值是相对于所依赖约束的偏移量。mas_offset()也可以不写,默认偏移0。
UIView *demoView = [[UIView alloc] init];
demoView.backgroundColor = UIColor.greenColor;
[self.view addSubview:demoView];
[demoView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.view.mas_left).mas_offset(50);//左边相对于 self.view 的 left 偏移50个单位
make.right.mas_equalTo(self.view.mas_right).mas_offset(-50);//右边相对于 self.view 的 right 偏移-50个单位
make.top.mas_equalTo(self.view.mas_top).mas_offset(100);//顶边相对于 self.view 的 top 偏移100个单位
make.bottom.mas_equalTo(self.view.mas_bottom).mas_offset(-100);//底边相对于 self.view 的 bottom 偏移-100个单位
}];
- 第二种。mas_equalTo()只需要传入相对的约束的视图,不需要指定约束边,默认取前面第一个需要添加约束的边
UIView *demoView = [[UIView alloc] init];
demoView.backgroundColor = UIColor.greenColor;
[self.view addSubview:demoView];
[demoView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.view).mas_offset(50);//等价于 make.left.mas_equalTo(self.view.mas_left).mas_offset(50);
make.right.mas_equalTo(self.view).mas_offset(-50);//等价于 make.right.mas_equalTo(self.view.mas_right).mas_offset(-50);
make.top.mas_equalTo(self.view).mas_offset(100);//等价于 make.top.mas_equalTo(self.view.mas_top).mas_offset(100);
make.bottom.mas_equalTo(self.view).mas_offset(-100);//等价于 make.bottom.mas_equalTo(self.view.mas_bottom).mas_offset(-100);
}];
- 第三种。mas_equalTo() 传入一个值,这个值就是相对于依赖父视图对应相同约束的偏移量
UIView *demoView = [[UIView alloc] init];
demoView.backgroundColor = UIColor.greenColor;
[self.view addSubview:demoView];
[demoView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(50);//等价于 make.left.mas_equalTo(demoView.superview.mas_left).mas_offset(50);
make.right.mas_equalTo(-50);//等价于 make.right.mas_equalTo(demoView.superview.mas_right).mas_offset(-50);
make.top.mas_equalTo(100);//等价于 make.top.mas_equalTo(demoView.superview.mas_top).mas_offset(100);
make.bottom.mas_equalTo(-100);//等价于 make.bottom.mas_equalTo(demoView.superview.mas_bottom).mas_offset(-100);
}];
三种写法结果是一致的,效果图如下
看你个人喜欢用哪一种,我个人比较懒,喜欢用第三种,所以都是以第三种写法作为描述
居左上
YYLabel *leftTopLabel = [[YYLabel alloc] init];
leftTopLabel.backgroundColor = UIColor.redColor;
leftTopLabel.text = @"居左上";
leftTopLabel.textColor = UIColor.whiteColor;
leftTopLabel.textAlignment = NSTextAlignmentCenter;
leftTopLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
[demoView addSubview:leftTopLabel];
[leftTopLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_offset(0);
make.top.mas_equalTo(0);
make.height.mas_equalTo(100);
make.width.mas_equalTo(100);
}];
效果如下
居左下
YYLabel *leftBottomLabel = [[YYLabel alloc] init];
leftBottomLabel.backgroundColor = UIColor.redColor;
leftBottomLabel.text = @"居左下";
leftBottomLabel.textColor = UIColor.whiteColor;
leftBottomLabel.textAlignment = NSTextAlignmentCenter;
leftBottomLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
[demoView addSubview:leftBottomLabel];
[leftBottomLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_offset(0);
make.bottom.mas_equalTo(0);
make.height.mas_equalTo(100);
make.width.mas_equalTo(100);
}];
效果如下
居右上
YYLabel *rightTopLabel = [[YYLabel alloc] init];
rightTopLabel.backgroundColor = UIColor.redColor;
rightTopLabel.text = @"居右上";
rightTopLabel.textColor = UIColor.whiteColor;
rightTopLabel.textAlignment = NSTextAlignmentCenter;
rightTopLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
[demoView addSubview:rightTopLabel];
[rightTopLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_offset(0);
make.top.mas_equalTo(0);
make.height.mas_equalTo(100);
make.width.mas_equalTo(100);
}];
居右下
YYLabel *rightBottomLabel = [[YYLabel alloc] init];
rightBottomLabel.backgroundColor = UIColor.redColor;
rightBottomLabel.text = @"居右下";
rightBottomLabel.textColor = UIColor.whiteColor;
rightBottomLabel.textAlignment = NSTextAlignmentCenter;
rightBottomLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
[demoView addSubview:rightBottomLabel];
[rightBottomLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_offset(0);
make.bottom.mas_equalTo(0);
make.height.mas_equalTo(100);
make.width.mas_equalTo(100);
}];
垂直水平居中
YYLabel *centerLabel = [[YYLabel alloc] init];
centerLabel.backgroundColor = UIColor.redColor;
centerLabel.text = @"居中";
centerLabel.textColor = UIColor.whiteColor;
centerLabel.textAlignment = NSTextAlignmentCenter;
centerLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
[demoView addSubview:centerLabel];
[centerLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(0);
make.height.mas_equalTo(100);
make.width.mas_equalTo(100);
}];
子控件来撑起父控件的高度
平常在开发过程中,经常有这种情况就是父控件高度是根据子控件内容动态变化,用masonry来实现这个功能相当简单,这里有几个知识点;
- 约束类对象
MASConstraint
,通过点进mas_makeConstraints:
方法的实现,源码如下
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
block(constraintMaker);
return [constraintMaker install];
}
咋们暂且先不管 MASConstraintMaker
类,找到最后一句constraintMaker
对象调用了 install
方法并返回;进入到这个install
的实现,源码实现如下
- (NSArray *)install {
if (self.removeExisting) {
NSArray *installedConstraints = [MASViewConstraint installedConstraintsForView:self.view];
for (MASConstraint *constraint in installedConstraints) {
[constraint uninstall];
}
}
NSArray *constraints = self.constraints.copy;
for (MASConstraint *constraint in constraints) {
constraint.updateExisting = self.updateExisting;
[constraint install];
}
[self.constraints removeAllObjects];
return constraints;
}
其中最上面的那个判断条件在调用mas_remakeConstraints:
方法时会被执行到,咋们也不看。咋们看下面这一段,其实 self.constraints
数组 就是在mas_makeConstraints:
的 block 块中添加的所有约束对象,接下来 self.constraints 执行 copy 并遍历执行 constraint.updateExisting = self.updateExisting;
和[constraint install];
,for 循环体中的第一句是标记更新约束还是新添加的约束,第二句是对约束装载,如果把第二句给注视掉,则添加的所有约束都不会被添加上,各位可以试一试;在方法的最后 返回了constraints数组,这个数组里面装的是 MASConstraint
类对象,再回到上面 mas_makeConstraints:
方法中,最后的 return [constraintMaker install];
实际上就是返回另一个约束对象的数组,没问题把。咋们在调用mas_makeConstraints:
方法时可以用一个数组来接收,没毛病。。看代码
UIView *superView = [[UIView alloc] init];
superView.backgroundColor = UIColor.greenColor;
[self.view addSubview:superView];
NSArray *constraints = [superView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_offset(20);
make.right.mas_offset(-20);
make.top.mas_offset(100);
}];
咋们在来看两个方法,mas_offset()/mas_equalTo(),这两个方法其实就是一个宏,点进去看源码如此
#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__)))
#ifdef MAS_SHORTHAND_GLOBALS
#define equalTo(...) mas_equalTo(__VA_ARGS__)
#define greaterThanOrEqualTo(...) mas_greaterThanOrEqualTo(__VA_ARGS__)
#define lessThanOrEqualTo(...) mas_lessThanOrEqualTo(__VA_ARGS__)
#define offset(...) mas_offset(__VA_ARGS__)
#endif
mas_equalTo 对应 equalTo 方法,mas_offset 对应 valueOffset 方法,这两个其实就是 Block 执行体,返回是调用者对象(连式编程的标志性语法),这个对象也就是MASConstraint
类对象。继续下去。篇幅有点长,这个知识点就到这里把。
- 约束的卸载
uninstall
,使用MASConstraint
对象调用这个uninstall
,就会把约束从对应的view上卸载掉;如下代码
UIView *superView = [[UIView alloc] init];
superView.backgroundColor = UIColor.greenColor;
[self.view addSubview:superView];
NSArray *constraints = [superView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_offset(20);
make.right.mas_offset(-20);
make.top.mas_offset(100);
}];
//卸载约束
for (MASConstraint *constraint in constraints) {
[constraint uninstall];
}
等价于
UIView *superView = [[UIView alloc] init];
superView.backgroundColor = UIColor.greenColor;
[self.view addSubview:superView];
__block MASConstraint *top = nil;
__block MASConstraint *left = nil;
__block MASConstraint *right = nil;
[superView mas_makeConstraints:^(MASConstraintMaker *make) {
left = make.left.mas_offset(20);
right = make.right.mas_offset(-20);
top = make.top.mas_offset(100);
}];
//卸载约束
[left uninstall];
[right uninstall];
[top uninstall];
- 约束的装载
install
,使用MASConstraint
对象调用这个install
,就会把约束装载到对应的view上;如下代码
UIView *superView = [[UIView alloc] init];
superView.backgroundColor = UIColor.greenColor;
[self.view addSubview:superView];
NSArray *constraints = [superView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_offset(20);
make.right.mas_offset(-20);
make.top.mas_offset(100);
}];
//装载约束
//for (MASConstraint *constraint in constraints) {
// [constraint install];
//}
等价于
UIView *superView = [[UIView alloc] init];
superView.backgroundColor = UIColor.greenColor;
[self.view addSubview:superView];
__block MASConstraint *top = nil;
__block MASConstraint *left = nil;
__block MASConstraint *right = nil;
[superView mas_makeConstraints:^(MASConstraintMaker *make) {
left = make.left.mas_offset(20);
right = make.right.mas_offset(-20);
top = make.top.mas_offset(100);
}];
//装载约束
//[left install];
//[right install];
//[top install];
预备知识讲完了,开始完成功能
- 首先定义三个全局属性必须得用到的
@interface Demo2ViewController ()
@property (nonatomic, weak) UIView *superView;
@property (nonatomic, weak) UIView *bottomView;
@property (nonatomic, weak) MASConstraint *bottom;
@end
- 写一个
createDemo
方法来实现案列, 并调用这个方法
- (void)viewDidLoad {
[super viewDidLoad];
[self createDemo];
}
- (void)createDemo {
//...案例代码在这里实现
}
- 创建
superView
,不给 superView 高度,高度通过他的子视图给撑起来
- (void)createDemo {
UIView *superView = [[UIView alloc] init];
superView.backgroundColor = UIColor.greenColor;
[self.view addSubview:superView];
[superView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(20);
make.right.mas_equalTo(-20);
make.top.mas_equalTo(100);
}];
}
- 创建一个添加按钮,没点击一下添加一个view在这个添加按钮下面
- (void)createDemo {
/*。。。。*/
UIButton *button = [[UIButton alloc] init];
[button setTitle:@"增加" forState:UIControlStateNormal];
button.backgroundColor = UIColor.redColor;
[button addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside];
[superView addSubview:button];
[button mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(10);
make.top.mas_equalTo(10);
make.right.mas_equalTo(-10);
self.bottom = make.bottom.mas_equalTo(-10);//记录下这个约束对象
make.height.equalTo(@(100));
}];
}
- 在
superView
的下方添加一个blueView
,这个视图blueView
的顶部始终距离superView
的底部10
- (void)createDemo {
/*。。。。*/
UIView *blueView = [[UIView alloc] init];
blueView.backgroundColor = UIColor.blueColor;
[self.view addSubview:blueView];
[blueView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(20);
make.right.mas_equalTo(-20);
make.top.mas_equalTo(superView.mas_bottom).mas_offset(10);
make.height.mas_equalTo(@(100));
}];
}
- 把
superView
赋值给self.superView
,把button
赋值给self.bottomView
- (void)createDemo {
/*。。。。*/
self.superView = superView;
self.bottomView = button;
}
运行效果图如下
- 实现添加方法
action:
,就能实现动态撑大父视图了
static int num = 0;
- (void)action:(UIButton *)button {
//卸载旧的底部约束
[self.bottom uninstall];
num += 1;
YYLabel *view = [[YYLabel alloc] init];
view.backgroundColor = UIColor.redColor;
view.text = [NSString stringWithFormat:@"控件%d", num];
view.textAlignment = NSTextAlignmentCenter;
view.textVerticalAlignment = YYTextVerticalAlignmentCenter;
[self.superView addSubview:view];
//给新 view 添加约束
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.superView.mas_left).offset(10);
make.top.mas_equalTo(self.bottomView.mas_bottom).offset(10);
make.right.mas_equalTo(self.superView.mas_right).offset(-10);
//添加新的底部约束
self.bottom = make.bottom.mas_equalTo(self.superView.mas_bottom).offset(-10);
make.height.equalTo(@(100));
}];
self.bottomView = view;
}
效果图如下
masonry 在 UIScrollView 中的运用
masonry + UIScrollView 通过两个示例,一个是水平方向,另一个垂直方向,这也是平常开发中会遇到的。在使用masonry对UIScrollView设置约束后,contentSize属性就不管用了,而需要通过masonry 的规则在scrollView中添加一个 contentView,其它的子视图全部添加到 contentView 上,让contentView来撑起UIScrollview的 contentSize。
水平方向滑动
- 第一步创建一个Scrollview
// 水平方向滚动视图
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.backgroundColor = UIColor.greenColor;
scrollView.pagingEnabled = YES;
[self.view addSubview:scrollView];
//设置 Scrollview 的约束
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.view).offset(100);
make.left.mas_equalTo(10);
make.right.mas_equalTo(-10);
make.bottom.mas_equalTo(-100);
}];
- 创建一个 contentView 放到Scrollview上,并设置约束
// 设置scrollView的子视图,即过渡视图contentSize
UIView *contentView = [[UIView alloc] init];
[scrollView addSubview:contentView];
[contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(scrollView);
make.height.mas_equalTo(scrollView);
}];
- 动态添加子视图到 contentView 上
UIView *previousView = nil;
for (int i = 0; i < 10; i++) {
YYLabel *label = [[YYLabel alloc] init];
label.textAlignment = NSTextAlignmentCenter;
label.numberOfLines = 2;
label.backgroundColor = UIColor.redColor;
label.text = [NSString stringWithFormat:@"水平方向\n第 %d 个视图", (i + 1)];
// 添加到父视图,并设置过渡视图中子视图的约束
[contentView addSubview:label];
[label mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(contentView).offset(20);
make.bottom.equalTo(contentView).offset(-20);
make.width.equalTo(scrollView).offset(-40);
if (previousView) {
make.left.mas_equalTo(previousView.mas_right).offset(40);
} else {
make.left.mas_equalTo(20);
}
}];
previousView = label;
}
- 设置 contentView 的right约束,这个是很关键的位置
//设置将影响到scrollView的contentSize
[contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(previousView.mas_right).offset(20);
}];
运行结果如下
垂直方向滑动
垂直方向上跟水平方向上的实现方式大致相同,我就直接粘代码过来了
@interface Demo3ViewController ()
@property (nonatomic, weak) UIView *superView;
@property (nonatomic, weak) UIView *bottomView;
@property (nonatomic, weak) MASConstraint *bottom;
@end
@implementation Demo3ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self createDemo];
}
- (void)createDemo {
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.backgroundColor = UIColor.greenColor;
[self.view addSubview:scrollView];
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(0);
make.right.mas_equalTo(-10.0);
make.height.mas_equalTo(self.view).offset(-100);
}];
UIView *superView = [[UIView alloc] init];
superView.backgroundColor = UIColor.greenColor;
[scrollView addSubview:superView];
[superView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(scrollView).with.insets(UIEdgeInsetsZero);
make.width.mas_equalTo(scrollView);
}];
UIButton *button = [[UIButton alloc] init];
[button setTitle:@"增加" forState:UIControlStateNormal];
button.backgroundColor = UIColor.redColor;
[button addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside];
[superView addSubview:button];
[button mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.mas_equalTo(0);
make.height.mas_equalTo(100);
make.top.mas_equalTo(20);
}];
self.superView = superView;
self.bottomView = button;
//设置 scrollview 的 contentSize
[self.superView mas_makeConstraints:^(MASConstraintMaker *make) {
self.bottom = make.bottom.mas_equalTo(self.bottomView.mas_bottom);
}];
}
static int num = 0;
- (void)action:(UIButton *)button {
//取消底部约束
[self.bottom uninstall];
num += 1;
YYLabel *view = [[YYLabel alloc] init];
view.backgroundColor = UIColor.redColor;
view.text = [NSString stringWithFormat:@"控件%d", num];
view.textAlignment = NSTextAlignmentCenter;
view.textVerticalAlignment = YYTextVerticalAlignmentCenter;
[self.superView addSubview:view];
//给新 view 添加约束
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.superView).offset(20);
make.right.mas_equalTo(self.superView).offset(-20);
make.height.mas_equalTo(100);
make.top.mas_equalTo(self.bottomView.mas_bottom).offset(20);
}];
//记录最下面的 view
self.bottomView = view;
//设置新的 contentSize
[self.superView mas_makeConstraints:^(MASConstraintMaker *make) {
self.bottom = make.bottom.mas_equalTo(self.bottomView.mas_bottom);
}];
}
结果如下
masonry 多列等宽
固定间距
masonry提供了实现多列等高API,指定 item 之间的间距,然后 item 的宽或者高动态变化
/**
* distribute with fixed spacing
*
* @param axisType which axis to distribute items along
* @param fixedSpacing the spacing between each item
* @param leadSpacing the spacing before the first item and the container
* @param tailSpacing the spacing after the last item and the container
*/
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedSpacing:(CGFloat)fixedSpacing leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;
用法如下
- (void)createDemo {
NSMutableArray *views = [NSMutableArray array];
for (NSInteger i = 0; i < 3; i++) {
YYLabel *item = [[YYLabel alloc] init];
view.backgroundColor = UIColor.greenColor;
view.textAlignment = NSTextAlignmentCenter;
view.text = [NSString stringWithFormat:@"%ld",i];
[views addObject:item];
[self.view addSubview:item];
}
[views mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(self.view);
make.height.mas_equalTo(100);
}];
[views mas_distributeViewsAlongAxis:MASAxisTypeHorizontal
withFixedSpacing:50
leadSpacing:10
tailSpacing:20];
}
固定 item 宽度
masonry提供了实现多列等高API,指定 item 宽度或者高度,然后 item 之间的间距动态变化,方法描述
/**
* distribute with fixed item size
*
* @param axisType which axis to distribute items along
* @param fixedItemLength the fixed length of each item
* @param leadSpacing the spacing before the first item and the container
* @param tailSpacing the spacing after the last item and the container
*/
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedItemLength:(CGFloat)fixedItemLength leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;
用法
- (void)createDemo {
NSMutableArray *views = [NSMutableArray array];
for (NSInteger i = 0; i < 3; i++) {
YYLabel *item = [[YYLabel alloc] init];
item.backgroundColor = UIColor.greenColor;
item.textAlignment = NSTextAlignmentCenter;
item.text = [NSString stringWithFormat:@"%ld",i];
[views addObject:item];
[self.view addSubview:item];
}
[views mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(self.view);
make.height.mas_equalTo(100);
}];
[views mas_distributeViewsAlongAxis:MASAxisTypeHorizontal
withFixedItemLength:100
leadSpacing:50
tailSpacing:50];
}
masonry 设置宽高比例
在 masonry 提供了multipliedBy()
函数用来处理布局比例问题
,API
/**
* Sets the NSLayoutConstraint multiplier property
*/
- (MASConstraint * (^)(CGFloat multiplier))multipliedBy;
用法
- (void)createDemo {
//示例1
YYLabel *superView = [[YYLabel alloc] init];
superView.text = @"示例2";
superView.textAlignment = NSTextAlignmentCenter;
superView.backgroundColor = UIColor.redColor;
[self.view addSubview:superView];
[superView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(0);
//superView.width = superView.height = self.view.width * 0.5;
make.width.height.mas_equalTo(self.view.mas_width).multipliedBy(0.5);
}];
//示例2
YYLabel *subView = [[YYLabel alloc] init];
subView.text = @"示例2";
subView.textAlignment = NSTextAlignmentCenter;
subView.backgroundColor = UIColor.blueColor;
[superView addSubview:subView];
[subView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(0);
make.width.mas_equalTo(superView);
//subView.height = subView.width * 0.5;
make.height.mas_equalTo(subView.mas_width).multipliedBy(0.5);
}];
}
运行结果如下
masonry UIButton 自适应宽度
在 UIButton 自使用中需要使用到 mas_greaterThanOrEqualTo(value) 以及 mas_lessThanOrEqualTo(value)方法,mas_greaterThanOrEqualTo(value) 大于等于 value,mas_lessThanOrEqualTo(value)则是小于等于value
示例如下
UIButton *btn = [[UIButton alloc] init];
btn.backgroundColor = [UIColor blueColor];
[btn setTitle:@"UIButton宽度" forState:UIControlStateNormal];
[btn setImage:[UIImage imageNamed:@"icon"] forState:UIControlStateNormal];
[btn addTarget:self action:@selector(clicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(self.view);
make.height.mas_equalTo(@[btn.titleLabel.mas_height, btn.imageView.mas_height]);
make.width.mas_lessThanOrEqualTo(kScreenWidth);
}];
clicked:方法实现
- (void)clicked:(UIButton *)btn {
[btn setTitle:[btn.currentTitle stringByAppendingString:@"自适应"] forState:UIControlStateNormal];
}
看看效果怎么样
UIButton 还有很多玩法,这里就不一一举例了
masonry UILabel 自适应宽度/高度
- 对于 UILabel 自适应宽度只需要使用
mas_lessThanOrEqualTo()
方法就能达到 - 当宽度达到极限后开始换行需要设置两个参数,UILabel的 numberOfLines 属性和 preferredMaxLayoutWidth 属性,
代码实现
//普通文本
- (void)createDemo {
self.label2 = [[UILabel alloc]init];
self.label2.tag = 100;
[self.view addSubview:self.label2];
self.label2.text = @"最近是用Masonry";
self.label2.backgroundColor = UIColor.redColor;
[self.label2 setPreferredMaxLayoutWidth:self.view.width - 30];
self.label2.numberOfLines = 0;
[self.label2 setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.label2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(100);
make.left.mas_equalTo(15);
}];
UIButton *btn = [[UIButton alloc] init];
btn.backgroundColor = [UIColor blueColor];
[btn setTitle:@"添加文字" forState:UIControlStateNormal];
[btn addTarget:self action:@selector(clicked) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.label2.mas_bottom).mas_offset(20);
make.centerX.mas_equalTo(self.view);
make.height.mas_equalTo(50);
make.width.mas_lessThanOrEqualTo(kScreenWidth);
}];
}
- (void)clicked {
self.label2.text = [self.label2.text stringByAppendingString:@"Masonry自动布局UILabel"];
}
结果如下
masonry YYLabel 自适应宽度/高度
代码实现
- (void)createDemo {
self.label1 = [[YYLabel alloc] init];
self.label1.text = @"最近是用Masonry自动布局UILabel的时候,;这些东西之后,label还是没有换行。最近是用Masonry自动布局UILabel的时候,";
self.label1.backgroundColor = UIColor.greenColor;
self.label1.numberOfLines = 0;
self.label1.preferredMaxLayoutWidth = self.view.width - 30;
[self.view addSubview:self.label1];
[self.label1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(100);
make.left.mas_equalTo(15);
}];
UIButton *btn = [[UIButton alloc] init];
btn.backgroundColor = [UIColor blueColor];
[btn setTitle:@"添加文字" forState:UIControlStateNormal];
[btn addTarget:self action:@selector(clicked) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.label1.mas_bottom).mas_offset(20);
make.centerX.mas_equalTo(self.view);
make.height.mas_equalTo(50);
make.width.mas_lessThanOrEqualTo(kScreenWidth);
}];
}
- (void)clicked {
self.label1.text = [self.label1.text stringByAppendingString:@"Masonry自动布局YYLabel"];
}
结果如下
masonry 实现动态 UITabelViewCell
先看效果
demo实现得很粗糙,但是基本功能都实现了。实现动态 UITabelViewCell 需要了解到的知识点
- 不设置cell的高度
- 不实现返回cell高度的代理方法
- 设置 UITabelViewCell的estimatedRowHeight属性
- 将tableview的rowHeight属性设置为UITableViewAutomaticDimension
示例如下
- (UITableView *)tableView {
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.estimatedRowHeight = 100;
_tableView.rowHeight = UITableViewAutomaticDimension;
[_tableView registerClass:Demo8Cell.class forCellReuseIdentifier:@"cellID"];
[self.view addSubview:_tableView];
}
return _tableView;
}
关于 tableview 需要设置的就这些,剩下的在 tableviewCell 的动态高度在cell内部设置
关于 Demo8Cell 内部实现如下
.h
@class Demo8Model;
NS_ASSUME_NONNULL_BEGIN
@interface Demo8Cell : UITableViewCell
@property (nonatomic, strong) UILabel *messageLabel;
- (void)setmessage:(Demo8Model *)message;
@end
.m
@interface Demo8Cell ()
@property (nonatomic, strong) UIView *picContentView;
@property (nonatomic, strong) UIView *timerView;
@property (nonatomic, strong) UIView *likeView;
@end
@implementation Demo8Cell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
[self createUI];
}
return self;
}
- (void)createUI {
self.messageLabel = [[UILabel alloc] init];
self.messageLabel.numberOfLines = 0;
[self.contentView addSubview:self.messageLabel];
[self.messageLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(8);
make.left.mas_equalTo(10);
make.right.mas_equalTo(-10);
}];
self.picContentView = [[UIView alloc]init];
self.picContentView.backgroundColor = UIColor.grayColor;
[self.contentView addSubview:self.picContentView];
[self.picContentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.messageLabel.mas_bottom).offset(15);
make.left.mas_offset(50);
make.right.mas_offset(-20);
}];
self.timerView = [[UIView alloc]init];
self.timerView.backgroundColor = UIColor.redColor;
[self.contentView addSubview:self.timerView];
[self.timerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.picContentView.mas_bottom).mas_offset(10);
make.left.mas_equalTo(50);
make.height.mas_equalTo(30);
make.width.mas_equalTo(50);
//关键位置
make.bottom.mas_equalTo(-8);
}];
self.likeView = [[UIView alloc] init];
self.likeView.backgroundColor = UIColor.redColor;
[self.contentView addSubview:self.likeView];
[self.likeView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.picContentView.mas_bottom).mas_offset(10);
make.right.mas_equalTo(-20);
make.height.mas_equalTo(30);
make.width.mas_equalTo(50);
}];
}
- (void)setmessage:(Demo8Model *)message {
// 创建一个可变属性字符串
NSMutableAttributedString *finalStr = [[NSMutableAttributedString alloc] init];
// 创建姓名
NSAttributedString *nameStr = [[NSAttributedString alloc] initWithString:message.name attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:16], NSForegroundColorAttributeName: [UIColor redColor]}];
// 创建发言内容
NSAttributedString *messageStr = [[NSAttributedString alloc] initWithString:message.message attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:16], NSForegroundColorAttributeName: [UIColor blackColor]}];
// 拼接上两个字符串
[finalStr appendAttributedString:nameStr];
[finalStr appendAttributedString:messageStr];
self.messageLabel.attributedText = finalStr;
//移除所有图片
[self.picContentView removeAllSubviews];
[self createDemo:message.picNum];
}
- (void)createDemo:(NSInteger)itemNum {
//假设要显示 num 个item
NSInteger num = itemNum;
//每行显示的个数
NSInteger count = 3;
//显示的总行数
NSInteger rowNum = (num/count) + ((NSInteger)(num%count>0));
UIView *lastView = nil;
for (int i = 0; i < rowNum; i ++) {
NSMutableArray *masonryViewArray = [NSMutableArray array];
for (int j = 0; j < count; j ++) {
UIView *view = [[UIView alloc] init];
if ((i * count) + j > num-1) {
view.backgroundColor = [UIColor clearColor];
} else {
view.backgroundColor = [UIColor redColor];
}
[self.picContentView addSubview:view];
[masonryViewArray addObject:view];
lastView = view;
}
// 固定 item 之间的间距,item 的宽或者高自动缩放
[masonryViewArray mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:30 leadSpacing:10 tailSpacing:10];
// 设置array的垂直方向的约束
[masonryViewArray mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(@((100 * i) + 10));
make.height.equalTo(@80);
}];
}
if (lastView) {
[self.picContentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(lastView.mas_bottom).mas_offset(20);
}];
}
}
@end