在经过frame时代的布局计算后,目前进入了autolayout 布局。相对之前frame布局的算算算,autolayout时代则要好的多,只需要计算控件之间的相对距离。因此布局简洁了不少。
传统的用代码设置autolayout十分复杂,因此这里我们使用一款叫做Masonry的开源框架,它封装了IOS原生代码设置约束的方法。使我们能够更简便的使用代码进行autolayout布局。
下载地址:https://github.com/SnapKit/Masonry。
既然上面已经介绍了用代码设计的框架,这里我们还需要一个根据约束来对cell进行计算高度的框架.FDTemplateLayoutCell.
下载地址https://github.com/forkingdog/UITableView-FDTemplateLayoutCell
好了废话不多说我们开始今天的项目。
实验目的
1.使用masonry 来给一个表格中的cell设置约束。并且使用FDTemplateLayoutCell来对设置好约束的cell进行行高激素啊。
实验效果
图一 当文本行高度小于头像的高度时。
图二 当文本行高度大于头像的高度时
实现方法。
首先我们创建一个cell,并且使用Masonry进行代码约束设置。代码如下
- (void) setupLayout {
__weaktypeof(self) weakSelf =self;
UIImageView*contentImageView = [[UIImageViewalloc]init];
// contentImageView.contentMode = UIViewContentModeScaleAspectFit;
[self.contentViewaddSubview:contentImageView];
self.imageV= contentImageView;
UIImageView*headImageV = [[UIImageViewalloc]init];
[self.contentViewaddSubview:headImageV];
self.headImageV= headImageV;
UILabel* contentLabel = [[UILabelalloc]init];
contentLabel.font= [UIFontsystemFontOfSize:13.0f];
contentLabel.textColor= [UIColorredColor];
contentLabel.numberOfLines=0;
contentLabel.textAlignment=NSTextAlignmentNatural;
self.contentLabel= contentLabel;
[self.contentViewaddSubview:contentLabel];
[contentImageViewmas_makeConstraints:^(MASConstraintMaker*make) {
make.top.equalTo(weakSelf.contentView.mas_top).offset(0);
make.left.equalTo(weakSelf.contentView.mas_left).offset(0);
make.right.equalTo(weakSelf.contentView.mas_right).offset(0);
//make.height.equalTo(weakSelf.contentView.mas_width).multipliedBy(0.5);
make.bottom.equalTo(headImageV.mas_top).offset(-10);
}];
[headImageVmas_makeConstraints:^(MASConstraintMaker*make) {
make.size.mas_equalTo(CGSizeMake(60,60));
make.left.equalTo(weakSelf.contentView.mas_left).offset(10);
make.top.equalTo(contentImageView.mas_bottom).offset(10);
// make.bottom.equalTo(weakSelf.contentView.mas_bottom).offset(-10);
make.bottom.equalTo(weakSelf.contentView.mas_bottom).offset(-10).priorityMedium(0);
}];
[contentLabelmas_makeConstraints:^(MASConstraintMaker*make) {
make.top.equalTo(contentImageView.mas_bottom).offset(10);
make.left.equalTo(headImageV.mas_right).offset(10);
make.right.equalTo(weakSelf.contentView.mas_right).offset(-10);
make.bottom.equalTo(weakSelf.contentView.mas_bottom).offset(-10).priorityHigh(0);
}];
}
这里要注意的是,我们添加的控件是添加到了cell中的cotentView里面,因此,再进行父类约束设置的时候,就必须用contentView来进行参照,而不是cell中的View. 比如设置一个UIImageView 它的在其父类视图中,上下左右的间距都是0,它在父视图中展示的效果就应该是一个,铺满父视图的视图。但是如果你添加到contentView上面,却用的是View来进行约束参照。约束就不会起作用,FDTemplateLayoutCell也不会计算出准确的高度。
在设置好约束以后,因为这些控件都是木有数据的,所以现在就只有约束,当然,光有约束我们没有数据,所以我们还是看不出来布局效果。
为了让我们看出布局的效果,所以我们就要为这些控件提供一个写入数据的接口。
- (void)setObject:(entity*)object {
_object= object;
[_imageVsetImage:[UIImageimageNamed:@"contentImage"]];
[_headImageVsetImage:[UIImageimageNamed:@"headImage"]];
[_contentLabelsetText:@"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"];
}
这样一来我们的控件里面也有数据了,下面我们就要用FDTemplateLayoutCell来自动计算我们的cell的高度了。
控制器中的实现代码如下。
- (NSInteger) tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section {
returnself.dataArray.count;
}
- (CGFloat) tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath {
return[tableViewfd_heightForCellWithIdentifier:@"masoryCell"cacheByIndexPath:indexPathconfiguration:^(masoryCell* cell) {
//配置cell的数据源,和"cellForRow"干的事一致,比如:
cell.object=self.dataArray[indexPath.row];
}]+20;
}
- (UITableViewCell*) tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
masoryCell* cell =[tableViewdequeueReusableCellWithIdentifier:@"masoryCell"forIndexPath:indexPath];
// UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"customeTableViewCell"];
cell.object=self.dataArray[indexPath.row];
returncell;
}
通过FDTemplateLayoutCell 提供的分类方法
[tableViewfd_heightForCellWithIdentifier:@"masoryCell"cacheByIndexPath:indexPathconfiguration:^(masoryCell* cell) {
//配置cell的数据源,和"cellForRow"干的事一致,比如:
cell.object=self.dataArray[indexPath.row];
}];
就可以为我们计算出cell的高度了
这里要注意的是,必须注册我们的设好的cell到talbeView中 ,这样我们才能复用,这些cell.
提示:在使用masonry为cell设置约束的时候,必须在cell初始化的时候实现,不能在写入数据的时候,为cell设置约束。不然会导致计算不出高度。
为了达到上图中的效果。
当Label的行高大于Image头像的时候,Label的设置的约束起作用。当Label小于头像图片的时候,就头像设置的约束起作用。
这里给出的解决办法是设置约束优先级。autoLayout 约束优先级,工作的原理是这样的:如上图中所示:头像的上约束是,相对于大图的底部间隔10的单位,下约束是相对于contentView底部间隔10个单位。同样Label设置的上下约束也是和头像视图是一致的。所以我们这里设置label的下约束优先级高于头像的下约束,这里头像视图的大小是固定是60x60。而Label高度又是不固定的,所以系统先判断,如果label的行高小于或者等于头像视图的时候。系统默认两个视图的下约束不冲突。各自按照设置好的约束进行设置,所以头像视图的高度等于label视图的高度,因此头像视图距cotentView视图底部为10个单位。但是一旦label的高度大于头像视图的高度,则系统判断优先级更高的label视图的下约束生效。所以就让label的下约束生效。因此label的底部距离contentView视图的底部为10个单位。而头像视图的下约束变为距离contentView底部Label的高度 减去 头像视图的高度 再加上10个单位的距离。
本项目下载地址 https://github.com/coderFrankenstain/fdtableviewcell
关注微信公众号获得更多源码