iOS自动布局框架之Masonry.docx
- 文档编号:10939554
- 上传时间:2023-02-23
- 格式:DOCX
- 页数:13
- 大小:19.58KB
iOS自动布局框架之Masonry.docx
《iOS自动布局框架之Masonry.docx》由会员分享,可在线阅读,更多相关《iOS自动布局框架之Masonry.docx(13页珍藏版)》请在冰豆网上搜索。
iOS自动布局框架之Masonry
iOS自动布局框架之Masonry
目前iOS开发中大多数页面都已经开始使用InterfaceBuilder的方式进行UI开发了,但是在一些变化比较复杂的页面,还是需要通过代码来进行UI开发的。
而且有很多比较老的项目,本身就还在采用纯代码的方式进行开发。
而现在iPhone和iPad屏幕尺寸越来越多,虽然开发者只需要根据屏幕点进行开发,而不需要基于像素点进行UI开发。
但如果在项目中根据不同屏幕尺寸进行各种判断,写死坐标的话,这样开发起来是很吃力的。
所以一般用纯代码开发UI的话,一般都是配合一些自动化布局的框架进行屏幕适配。
苹果为我们提供的适配框架有:
VFL、UIViewAutoresizing、AutoLayout、SizeClasses等。
其中AutoLayout是使用频率最高的布局框架,但是其也有弊端。
就是在使用UILayoutConstraint的时候,会发现代码量很多,而且大多都是重复性的代码,以至于好多人都不想用这个框架。
今天要给大家介绍的这个框架Masonry是基于UILayoutConstraint封装的。
这个框架已经出来有三年了,现在也比较成熟了。
Masonry开源地址Masonry。
Masonry简介
Masonry是一个对系统NSLayoutConstraint进行封装的第三方自动布局框架,采用链式编程的方式提供给开发者API。
系统AutoLayout支持的操作,Masonry都支持,相比系统API功能来说,Masonry是有过之而无不及。
Masonry采取了链式编程的方式,代码理解起来非常清晰易懂,而且写完之后代码量看起来非常少。
之前用NSLayoutConstraint写很多代码才能实现的布局,用Masonry最少一行代码就可以搞定。
Masonry是同时支持Mac和iOS两个平台的,在这两个平台上都可以使用Masonry进行自动布局。
我们可以从MASUtilities.h文件中,看到下面的定义,这就是Masonry通过宏定义的方式,区分两个平台独有的一些关键字。
通过CocoaPods,在项目中可以很容易的集成Masonry。
pod'Masonry'1
学习曲线
对于初学者学习纯代码AutoLayout,我建议还是先学会InterfaceBuilder方式的AutoLayout,领悟苹果对自动布局的规则和思想,然后再把这套思想嵌套在纯代码上。
这样学习起来更好入手,也可以避免踩好多坑。
在项目中设置的AutoLayout约束,起到对视图布局的标记作用。
设置好约束之后,程序运行过程中创建视图时,会根据设置好的约束计算frame,并渲染到视图上。
Masonry使用
在正式使用Masonry之前,最后先学会AutoLayout。
Masonry提供的的API有:
mas_makeConstraints()添加约束
mas_remakeConstraints()移除之前的约束,重新添加新的约束
mas_updateConstraints()更新约束
equalTo()参数是对象类型,一般是视图对象或者mas_width这样的坐标系对象
mas_equalTo()和上面功能相同,参数可以传递基础数据类型对象,可以理解为比上面的API更强大
width()用来表示宽度,例如代表view的宽度
mas_width()用来获取宽度的值。
和上面的区别在于,一个代表某个坐标系对象,一个用来获取坐标系对象的值
12345678910
说明:
上面例如equalTo或者width这样的,有时候需要涉及到使用mas_前缀,这在开发中需要注意作区分。
如果在当前类引入#import“Masonry.h”之前,用下面两种宏定义声明一下,就不需要区分mas_前缀。
例如:
//定义这个常量,就可以不用在开发过程中使用"mas_"前缀。
#defineMAS_SHORTHAND
//定义这个常量,就可以让Masonry帮我们自动把基础数据类型的数据,自动装箱为对象类型。
#defineMAS_SHORTHAND_GLOBALS1234
Masonry为了让代码使用和阅读更容易理解,所以直接通过点语法就可以调用,还添加了and和with两个方法。
这两个方法内部实际上什么都没干,只是在内部将self直接返回,功能就是为了更加方便阅读,对代码执行没有实际作用。
例如:
make.top.and.bottom.equalTo(self.containerView).with.offset(padding);1
其内部代码实现,实际上就是直接将self返回。
-(MASConstraint*)with{
returnself;
}123
约束和布局
关于更新约束布局相关的API,主要用以下四个API:
-(void)updateConstraintsIfNeeded调用此方法,如果有标记为需要重新布局的约束,则立即进行重新布局,内部会调用updateConstraints方法
-(void)updateConstraints重写此方法,内部实现自定义布局过程
-(BOOL)needsUpdateConstraints当前是否需要重新布局,内部会判断当前有没有被标记的约束
-(void)setNeedsUpdateConstraints标记需要进行重新布局1234
关于UIView重新布局相关的API,主要用以下三个API:
-(void)setNeedsLayout标记为需要重新布局
-(void)layoutIfNeeded查看当前视图是否被标记需要重新布局,有则在内部调用layoutSubviews方法进行重新布局
-(void)layoutSubviews重写当前方法,在内部完成重新布局操作123
常用方法
设置内边距
[self.yellowViewmas_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);
}];123456
通过insets简化设置内边距的方式。
[self.blueViewmas_makeConstraints:
^(MASConstraintMaker*make){
//下、右不需要写负号,insets方法中已经为我们做了取反的操作了。
make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(10,10,10,10));
}];1234
更新约束:
[self.greenViewmas_makeConstraints:
^(MASConstraintMaker*make){
make.center.equalTo(self.view);
//这里通过mas_equalTo给size设置了基础数据类型的参数,参数为CGSize的结构体
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.greenViewmas_updateConstraints:
^(MASConstraintMaker*make){
make.centerX.equalTo(self.view).offset(100);
make.size.mas_equalTo(CGSizeMake(100,100));
}];
});12345678910111213
大于等于和小于等于某个值的约束。
[self.textLabelmas_makeConstraints:
^(MASConstraintMaker*make){
make.center.equalTo(self.view);
//设置宽度小于等于200
make.width.lessThanOrEqualTo(@200);
//设置高度大于等于10
make.height.greaterThanOrEqualTo(@(10));
}];1234567
使用基础数据类型当做参数:
[self.redViewmas_makeConstraints:
^(MASConstraintMaker*make){
make.center.equalTo(self.view);
make.width.mas_equalTo(100);
make.height.mas_equalTo(100);
}];12345
设置约束优先级:
[self.redViewmas_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);
}];1234567
设置约束比例:
[self.redViewmas_makeConstraints:
^(MASConstraintMaker*make){
make.center.equalTo(self.view);
make.height.mas_equalTo(30);
make.width.equalTo(self.view).multipliedBy(0.2);
}];12345
UITableView动态Cell高度
在iOSUI开发过程中,UITableView的动态Cell高度一直都是个问题。
实现这样的需求,实现方式有很多种,只是实现起来复杂程度和性能的区别。
在不考虑性能的情况下,tableView动态Cell高度,可以采取估算高度的方式。
如果通过估算高度的方式实现的话,无论是纯代码还是InterfaceBuilder,都只需要两行代码就可以完成Cell自动高度适配。
需要设置tableView的rowHeight属性,这里设置为自动高度,告诉系统Cell的高度是不固定的,需要系统帮我们进行计算。
然后设置tableView的estimatedRowHeight属性,设置一个估计的高度。
(我这里用的代理方法,实际上都一样)。
其原理是:
在tableView被创建之后,系统会根据estimatedRowHeight属性设置的值,为tableView设置一个估计的值。
然后在Cell显示的时候再获取Cell的高度,并刷新tableView的contentSize。
涉及到的代码有:
-(void)tableViewConstraints{
[self.tableViewmas_makeConstraints:
^(MASConstraintMaker*make){
make.edges.equalTo(self.view);
}];
}
-(NSInteger)tableView:
(UITableView*)tableViewnumberOfRowsInSection:
(NSInteger)section{
returnself.dataList.count;
}
-(MasonryTableViewCell*)tableView:
(UITableView*)tableViewcellForRowAtIndexPath:
(NSIndexPath*)indexPath{
MasonryTableViewCell*cell=[tableViewdequeueReusableCellWithIdentifier:
LXZTableViewCellIdentifier];
[cellreloadViewWithText:
self.dataList[indexPath.row]];
returncell;
}
//需要注意的是,这个代理方法和直接返回当前Cell高度的代理方法并不一样。
//这个代理方法会将当前所有Cell的高度都预估出来,而不是只计算显示的Cell,所以这种方式对性能消耗还是很大的。
//所以通过设置estimatedRowHeight属性的方式,和这种代理方法的方式,最后性能消耗都是一样的。
-(CGFloat)tableView:
(UITableView*)tableViewestimatedHeightForRowAtIndexPath:
(NSIndexPath*)indexPath{
return50.f;
}
-(UITableView*)tableView{
if(!
_tableView){
_tableView=[[UITableViewalloc]initWithFrame:
CGRectZerostyle:
UITableViewStylePlain];
_tableView.delegate=self;
_tableView.dataSource=self;
//设置tableView自动高度
_tableView.rowHeight=UITableViewAutomaticDimension;
[_tableViewregisterClass:
[MasonryTableViewCellclass]forCellReuseIdentifier:
LXZTableViewCellIdentifier];
[self.viewaddSubview:
_tableView];
}
return_tableView;
}1234567891011121314151617181920212223242526272829303132333435
综合示例
-(void)setupFrame{
__weaktypeof(self)weakSelf=self;
//上传头像
UIButton*iconBtn=[[UIButtonalloc]init];
[iconBtnsetCornerRadius:
45];
[iconBtnsetBackgroundImage:
[UIImageimageNamed:
@"huantouxiang"]forState:
UIControlStateNormal];
[iconBtnaddTarget:
selfaction:
@selector(iconButton)forControlEvents:
UIControlEventTouchDown];
[self.viewaddSubview:
iconBtn];
self.iconBtn=iconBtn;
[self.iconBtnmas_makeConstraints:
^(MASConstraintMaker*make){
make.size.mas_equalTo(CGSizeMake(90,90));
make.centerX.equalTo(weakSelf.view);
make.top.width.offset(90);
}];
//上传社区头像文字提醒
UILabel*iconLabel=[[UILabelalloc]init];
iconLabel.textColor=c3;
iconLabel.text=@"上传社团头像";
iconLabel.font=[UIFontsystemFontOfSize:
15];
[self.viewaddSubview:
iconLabel];
[iconLabelmas_makeConstraints:
^(MASConstraintMaker*make){
make.centerX.equalTo(iconBtn);
make.top.equalTo(iconBtn.mas_bottom).with.offset(20);
}];
//社团编辑图标
UIImageView*editIcon=[[UIImageViewalloc]init];
editIcon.image=[UIImageimageNamed:
@"bianxie"];
[self.viewaddSubview:
editIcon];
[editIconmas_makeConstraints:
^(MASConstraintMaker*make){
make.size.mas_equalTo(CGSizeMake(25,20));
make.left.equalTo(weakSelf.view).with.offset(10);
make.top.equalTo(iconLabel.mas_bottom).with.offset(30);
}];
//社团名
UITextField*nameText=[[UITextFieldalloc]init];
nameText.placeholder=@"请填写社区名(社团名最多6个字)";
[self.viewaddSubview:
nameText];
self.nameText=nameText;
[nameTextmas_makeConstraints:
^(MASConstraintMaker*make){
make.height.mas_equalTo(@20);
make.centerY.equalTo(editIcon);
make.right.equalTo(weakSelf.view).with.offset(-10);
make.left.equalTo(editIcon.mas_right).with.offset(5);
}];
//分割线
UIImageView*xian=[[UIImageViewalloc]init];
xian.backgroundColor=DBColor(226,226,226);
[self.viewaddSubview:
xian];
[xianmas_makeConstraints:
^(MASConstraintMaker*make){
make.height.mas_equalTo(@1);
make.left.equalTo(weakSelf.view).with.offset(10);
make.right.equalTo(weakSelf.view).with.offset(-10);
make.top.equalTo(editIcon.mas_bottom).with.offset(5);
}];
//选择标签
UILabel*tagLabel=[[UILabelalloc]init];
tagLabel.text=@"选择标签";
tagLabel.textColor=c3;
tagLabel.font=[UIFontsystemFontOfSize:
15];
[self.viewaddSubview:
tagLabel];
[tagLabelmas_makeConstraints:
^(MASConstraintMaker*make){
make.height.mas_equalTo(@20);
make.width.mas_equalTo(@60);
make.left.equalTo(weakSelf.view).with.offset(10);
make.top.equalTo(xian).with.offset(35);
}];
//跳转标签选择
UITextField*tagText=[[UITextFieldalloc]init];
tagText.placeholder=@"美容颜";
tagText.borderStyle=UITextBorderStyleRoundedRect;
tagText.delegate=self;
[tagTextaddTarget:
selfaction:
@selector(textTag)forControlEvents:
UIControlEventTouchDown];
[self.viewaddSubview:
tagText];
[tagTextmas_makeConstraints:
^(MASConstraintMaker*make){
make.centerY.equalTo(tagLabel);
make.right.equalTo(weakSelf.view).with.offset(-10);
make.left.equalTo(tagLabel.mas_right).with.offset(5);
}];
//tagView
self.tagView=({
SKTagView*view=[SKTagViewnew];
view.backgroundColor=[UIColorclearColor];
view.padding=UIEdgeInsetsMake(0,0,0,0);
view.insets=15;
view.lineSpace=10;
__weakSKTagView*weakView=view;
view.didClickTagAtIndex=^(NSUIntegerindex){
//Removetag
[weakViewremoveTagAtIndex:
index];
};
view;
});
[self.viewaddSubview:
self.tagView];
[self.tagViewmas_makeConstraints:
^(MASConstraintMaker*make){
make.left.equalTo(weakSelf.view).with.offset(10);
make.right.equalTo(weakSelf.view).with.offset(-10);
make.top.equalTo(tagText.mas_bottom).with.offset(10);
}];
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- iOS 自动 布局 框架 Masonry