Masonry学习分享

不完整目录

UIScrollView 应用Masonry的正确用法

tableHeaderView使用Masonry

同向文字显示优先级

1.基础篇

1.1基础使用

1.1.1运行效果

Masonry学习分享

1.1.2关键代码

三个控件等高,红绿两个控件等宽

[greenView mas_makeConstraints:^(MASConstraintMaker *make) {

make.height.mas_equalTo(redView);

make.height.mas_equalTo(blueView)

make.width.mas_equalTo(redView);

}];

黄色在蓝色中居中显示(居中偏移可使用:make.center.equalTo(blueView).centerOffset(CGPointMake(50, 50));)

make.center.equalTo(blueView);

灰色在绿色区域中设置边距

make.edges.equalTo(greenView).insets(UIEdgeInsetsMake(20, 20, 20, 20));

1.2约束百分比

1.2.1运行效果

Masonry学习分享

1.2.2 关键代码

设置宽高比:multipliedBy、 dividedBy   

红色高度是页面的1/2

make.height.equalTo(self.view).dividedBy(2);

绿色宽度是自身高度2倍

make.width.mas_equalTo(greenView.mas_height).multipliedBy(2);

设置绿色宽和高不能超过红色

make.width.height.mas_equalTo(redView).priorityLow();

make.width.height.lessThanOrEqualTo(redView);

1.3 UIScrollView使用Masonry

1.3.1 运行效果

Masonry学习分享

1.3.2 关键代码

UIScrollView使用约束比较特殊,在添加到父视图上之后,需设置自己的大小及内容的长度。但对于scrollview和tableview,我们不能使用bottom来计算其高,因为这个属性对于scrollview和tableview来说,不用用来计算高度的,而是用于计算contentSize.height的。所以简单添加约束如下:

//设置其大小

make.edges.mas_equalTo(self.view);

// 让scrollview的contentSize随着内容的增多而变化

make.bottom.mas_equalTo(lastWidget.mas_bottom).offset(20);

这两句即可简单实现UIScrollView在页面中显示,如果页面内容高于屏幕时,可正常滑动,但内容很少时则不能滑动。解决该问题可请参照1.6正确的写法

1.4 单个约束启用、禁用

1.4.1运行效果

页面所有UILabel都设置收缩状态约束高度为40,点击某个label时,该UILabel根据内容大小动画展开,再次点击收缩。页面整体的UIScrollview根据内容高度自动扩展(原理同1.3)

Masonry学习分享

1.4.2 关键代码   MASViewConstraint (void)install   (void)uninstall

创建约束或更新约束时,可赋值该约束对象到itemConstraint,注意加__block

[label mas_makeConstraints:^(MASConstraintMaker *make) {

itemConstraint =  (MASViewConstraint *)make.height.mas_equalTo(40);

]};

执行约束的装载或卸载,注意,当在UITableViewCell中使用时,由于cell重用的机制,约束的赋值可能存在问题

[itemConstraint install];

[itemConstraint uninstall];

1.5 UITableViewCell中使用约束,及cell高度自动计算

1.5.1运行效果

Cell布局简单来讲分为标题、描述上下两部分,其中描述文字默认收缩,点击时展开,cell高度自动扩充。

Masonry学习分享

1.5.2关键代码 UITableViewCell+HDFTableViewCell

cell中指定作为最后一个视图以及最后一个视图最底部与cell的底部之间的距离

- (void)hdf_setCellLastView:(UIView *)lastView bottomOffset:(CGFloat)bottomOffset;

cell高度自动计算:静态方法自动计算cell高度 configBlock中为cell填充数据

+ (CGFloat)hdf_heightForIndexPath:(NSIndexPath *)indexPath configBlock:(HDFCellConfigBlock)configBlock;

注意:

1、hdf_setCellLastView 可以在cell初始化控件中调用,也可以在控件设置数据方法中调用。

2、cell中控件尽量不要对self.contentView.mas_bottom进行约束。除非该控件与其他控件没有top、bottom关联约束

3、cell中多行UILabel相对cell.contentView尽量使用left+width约束,避免使用left+right,后者容易产生多行文字高度计算不准确问题

4、cell中多行UILabel在iOS6上还需要设置preferredMaxLayoutWidth(项目已不关心iOS6,可忽略)。

5、项目中UITableViewCell+HDFTableViewCell 使用了cell高度的缓存,若要更新高度或者数据源做了改变,记得调用+(void)hdf_removeCellResource

1.6 UIScrollView 应用Masonry的正确用法

1.6.1运行效果

Masonry学习分享

1.6.2 关键代码

scrollView设置edge约束,该约束实际上确定scrollview的frame等于当前Vc视图大小

[self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {

make.edges.mas_equalTo(self.view);

}];

内容容器设置约束

[scrollContentView mas_makeConstraints:^(MASConstraintMaker *make) {

make.edges.equalTo(self.scrollView); //scrollContentView填满Scrollview

make.width.equalTo(self.scrollView);//等同于设置contentSize宽度

make.height.greaterThanOrEqualTo(self.scrollView).offset(1);//设置contentSize高度,加1像素offset保证内容不足一屏也能滑动

}];

内容容器要知道自己到底多高,所以最后一个控件要加底部约束

[bottomWidget mas_makeConstraints:^(MASConstraintMaker *make) {

make.bottom.equalTo(scrollContentView.mas_bottom).offset(-80);

}];

注意:

UIScrollView 使用Masonry时,尽量不要在scrollview上直接addview。而应该使用一个viewContainer,所有的控件放在viewContainer上。

关键是 !!!设置container与scrollView之间的约束!!!

scrollView的width或者bottom不能用来计算其Frame,因为这个属性对于scrollview和tableview来说,不用用来计算高度的,而是用于计算contentSize的

设置步骤简单来说:

1、设置scrollview的大小为屏幕大小

2、设置viewContainer宽度为scrollview宽,高度为内容高,但还要填充scrollview

1.7 UITableViewCell中隐藏控件更新布局及高度

1.7.1 运行效果

Masonry学习分享

1.7.2 关键代码

cell中设置最后控件及cell高度计算同 “1.5简单tableview布局”

分为两种情况,如果需要隐藏的控件高度是固定或是frame封装的控件(如果要隐藏的控制在最低端则直接调用hdf_setCellLastView即可,记得将其hidden掉)

if (isHidden) {

[_testCustomView mas_updateConstraints:^(MASConstraintMaker *make) {

make.height.equalTo(@0);

}];

}else{

[_testCustomView mas_updateConstraints:^(MASConstraintMaker *make) {

make.height.equalTo(@100);

}];

}

控件内容非固定,根据内容变化 实现原理是直接把下方控件顶部约束贴到该控件顶部,由于是remake方式,所以原有约束需保留

if (isHidden) {

testCustomView.hidden = YES;

[self.bottomWidget mas_remakeConstraints:^(MASConstraintMaker *make) {

make.top.mas_equalTo(_testCustomView.mas_top);

make.centerX.equalTo(@0);

}];

}else{

testCustomView.hidden = NO;

[self.bottomWidget mas_remakeConstraints:^(MASConstraintMaker *make) {

make.top.mas_equalTo(_testCustomView.mas_bottom);

make.centerX.equalTo(@0);

}];

}

2.动画篇

2.1动画更新、重建约束

2.1.1 运行效果

Masonry学习分享

2.1.2关键代码

updateViewConstraints setNeedsUpdateConstraints

页面中重写updateViewConstraints方法,当然即使不用该回调也可以实现动画,但苹果推荐在updateViewConstraints方法中更新、添加、重建约束;

当我们将update或remake约束代码放到updateViewConstraints这个方法中时,我们在viewDidLoad方法中可以不用再写约束

-(void)updateViewConstraints{

[super updateViewConstraints] 父类方法一定要调用

}

想要更新约束时添加动画,就需要调用关键的一行代码:setNeedsUpdateConstraints,这是选择对应的视图中的约束需要更新。

对于updateConstraintsIfNeeded这个方法并不是必须的,但是有时候不调用就无法起到我们的效果。但是,官方都是这么写的,从约束的更新原理上讲,这应该写上。我们要使约束立即生效,就必须调用layoutIfNeeded此方法。看下面的方法,就是动画更新约束的核心代码

-(void)startAnimation{

//告诉self.view约束需要更新

[self.view setNeedsUpdateConstraints];

//告诉self.view检测是否需要更新约束,若需要则更新,下面添加动画效果才起作用

[self.view updateConstraintsIfNeeded];

//frame更新,执行动画

[UIView animateWithDuration:0.3 animations:^{

[self.view layoutIfNeeded];

}];

}

3.应用篇

3.1 tableHeaderView使用Masonry

3.1.1运行效果

对于一些页面中使用UITableView时,如果头部布局较固定,个人建议使用tableHeaderView,利于代码结构及UI调整。

Masonry学习分享

3.1.2关键代码  layoutIfNeeded

使用frame定义一个customeHeaderView,之所以使用frame是由于tableHeaderView只支持frame来使用,因此不要对customeHeaderView添加约束

customeHeaderView = [[UIView alloc] initWithFrame:(CGRect){0,0,kScreenWidth,100}];

注意!!设置宽度为屏幕宽度而不是0,避免子控件设置宽度约束而报约束冲突警告

customeHeaderView中正常使用Masonry来添加子控件

调用tableView.tableHeaderView = customeHeaderView时,要放在最后。原因很简单:赋予正确的frame

-(void)updateTabelHeaderHeight{

[customeHeaderView layoutIfNeeded];

CGRect headerRect = customeHeaderView.frame;

headerRect.size.height = bottomWidget.frame.origin.y+ bottomWidget.frame.size.height;

customeHeaderView.frame  = headerRect;

tableView.tableHeaderView = customeHeaderView;

}当customeHeaderView中高度需要动态变化时,需重新调用上面updateTabelHeaderHeight方法

3.2 内容相对多个控件布局

3.2.1运行效果

(只有一个科室时,图一文字垂直居中显示,图二垂直上对齐)

Masonry学习分享    Masonry学习分享

3.2.2 关键代码

底部绿色Label设置约束为:

make.top.greaterThanOrEqualTo(ivAvatar.mas_bottom).offset(15);

make.top.equalTo(lblVerticalDesc.mas_bottom).offset(15);

如果想要科室文字垂直上对齐如图二,则都设置为greaterThanOrEqualTo

3.3文字区域等宽

3.3.1运行效果

Masonry学习分享

3.3.2关键代码

[lblNum1 mas_remakeConstraints:^(MASConstraintMaker *make) {

make.top.equalTo(@15);

make.left.equalTo(ivAvatar.mas_right);

make.width.mas_equalTo(@[lblNum2, lblNum3]);//可以传数组

}];

3.4同向文字显示优先级

3.4.1运行效果

Masonry学习分享

3.4.2关键代码  setContentHuggingPriority setContentCompressionResistancePriority

这两个方法是AutoLayout的api,Masonry是基于AutoLayout的封装。所以可以混合使用,可设置优先级及方向。

ContentCompressionResistance=不许挤我。这个属性的优先级(Priority)越高,越不“容易”被压缩,也就是说,当整体的空间装不下所有的View的时候,ContentCompressionResistance优先级越高的,显示的内容越完整

ContentHugging = 抱紧。 这个属性的优先级越高,整个View就要越“抱紧”View里面的内容。也就是View的大小不会随着父级View的扩大而扩大

[lblHorizontalDesc setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal];

[lblHorizontalDesc setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal];

4.问题篇

1、view一定是已经被首先addSubview的(不可以直接对tableHaderView进行约束)

2、约束的设置其实就是告诉系统你的控件各自的相对位置,也就是系统能计算出每个控件的实际frame

3、控制UItableViewCell中控件的高度或调整约束就可以动态适用cell高度计算,

4、cell中控件尽量不要对cell.contentView进行mas_bottom约束,除非这个控件没有mas_top约束;

5、cell中多行的UIlabel使用left、right约束有时会有UILabel高度计算不准确的问题,建议使用left+width;

6、使用Masonry的理念就是不用去计算文字的宽度及高度,如果需要自己计算,看看是不是约束能优化

7、一些基本的控件有内容时可不用设置高度约束,如:UILabel,UIimageView,UIButton等

demo下载链接:

HDFMasonryDemo副本.zip

上一篇:jQuery的width()、innerWidth()、outerWidth()方法


下一篇:[BZOJ 2456]Mode(神奇的抵销)