您好, , 海量一手媒体资源,专业、正规、高效,为企业提供一站式营销推广服务!
温馨提示
运营小帮手
一站式互联网营销服务平台
  全国免费咨询热线
0755-23071973
运营小帮手
软文发稿
PC端 选择媒体
更方便、更快捷!
查看媒体价格
软文发布、软文代写、百科制作、问答营销、微信营销、微信营销
查看媒体价格
当前位置: 运营小帮手首页 > 新闻中心 > 文章正文

iOS 开源HYBMasonryAutoCellHeight

还在手动计算UITableViewCell的行高吗?还在每次都因为需求变化一点就要大量调整cell的高度而烦恼吗?现在教大家如何通过Masonry的自动布局来实现自动计算cell的行高!!!

github没有找到基于Masonry自动计算行高的库,倒是找到了使用xib/storyboard在添加约束来自动计算行高的库,如:UITableView-FDTemplateLayoutCell

本人非常推崇Masonry来实现代码的自动布局,因此项目中都是使用Masonry布局的,为了自动计算行高,决定写一个扩展,以达到自动计算的效果,如此一来,开发者不用再关心那些非固定行高的cell的动态计算问题了。

设置关键依赖

要想自动计算出cell的行高,我们还需要指定以哪个视图作为cell的最后一个视图,比如我们最后要添加一条线,我们可以以这条线作为hyb_lastViewInCell,如果这条线还需要距离底部一定距离,那么可以设置hyb_bottomOffsetToCell

/**
*必传设置的属性,也就是在cell中的contentView内最后一个视图,用于计算行高
*例如,创建了一个按钮button作为在cell中放到最后一个位置,则设置为:self.hyb_lastVieInCell=button;
*即可。
*默认为nil,如果在计算时,值为nil,会crash
*/
@property(nonatomic,strong)UIView*hyb_lastViewInCell;

/**
*可选设置的属性,默认为0,表示指定的hyb_lastViewInCell到cell的bottom的距离
*默认为0.0
*/
@property(nonatomic,assign)CGFloathyb_bottomOffsetToCell;

计算行高API

要计算行高,只需要在UITableView的计算行高的代理方法中调用此API即可,下面的API是不缓存行高的:

/**
*通过此方法来计算行高,需要在config中调用配置数据的API
*
*@paramtableView必传,为哪个tableView缓存行高
*@paramconfig必须要实现,且需要调用配置数据的API
*
*@return计算的行高
*/
+(CGFloat)hyb_heightForTableView:(UITableView*)tableViewconfig:(HYBCellBlock)config;

若想要缓存行高,请使用此API:

/**
*@author黄仪标,16-01-2223:01:56
*
*此API会缓存行高
*
*@paramtableView必传,为哪个tableView缓存行高
*@paramconfig必须要实现,且需要调用配置数据的API
*@paramcache返回相关key
*
*@return行高
*/
+(CGFloat)hyb_heightForTableView:(UITableView*)tableView
config:(HYBCellBlock)config
cache:(HYBCacheHeight)cache;

//其中,需要使用指定的key传值
/**
*@author黄仪标,16-01-2221:01:09
*
*唯一键,通常是数据模型的id,保证唯一
*/
FOUNDATION_EXTERNNSString*constkHYBCacheUniqueKey;

/**
*@author黄仪标,16-01-2221:01:57
*
*对于同一个model,如果有不同状态,而且不同状态下高度不一样,那么也需要指定
*/
FOUNDATION_EXTERNNSString*constkHYBCacheStateKey;

/**
*@author黄仪标,16-01-2221:01:47
*
*用于指定更新某种状态的缓存,比如当评论时,增加了一条评论,此时该状态的高度若已经缓存过,则需要指定来更新缓存
*/
FOUNDATION_EXTERNNSString*constkHYBRecalculateForStateKey;

实现例子

效果图如下:

创建cell

我们看下实现-initWithStyle: reuseIdentifier:方法,因为我们要自动计算cell行高会自动调用此方法,因此一定要实现此方法来布局:

-(nonnullinstancetype)initWithStyle:(UITableViewCellStyle)style
reuseIdentifier:(nullableNSString*)reuseIdentifier{
if(self=[superinitWithStyle:stylereuseIdentifier:reuseIdentifier]){
self.mainLabel=[[UILabelalloc]init];
[self.contentViewaddSubview:self.mainLabel];
self.mainLabel.numberOfLines=0;
[self.mainLabelmas_makeConstraints:^(MASConstraintMaker*make){
make.left.mas_equalTo(15);
make.top.mas_equalTo(20);
make.right.mas_equalTo(-15);
make.height.mas_lessThanOrEqualTo(80);
}];
CGFloatw=[UIScreenmainScreen].bounds.size.width;
//应该始终要加上这一句
//不然在6/6plus上就不准确了
self.mainLabel.preferredMaxLayoutWidth=w-30;

self.descLabel=[[UILabelalloc]init];
[self.contentViewaddSubview:self.descLabel];
self.descLabel.numberOfLines=0;
[self.descLabelsizeToFit];
[self.descLabelmas_makeConstraints:^(MASConstraintMaker*make){
make.left.mas_equalTo(15);
make.right.mas_equalTo(-15);
make.top.mas_equalTo(self.mainLabel.mas_bottom).offset(15);
}];
//应该始终要加上这一句
//不然在6/6plus上就不准确了
self.descLabel.preferredMaxLayoutWidth=w-30;
self.descLabel.userInteractionEnabled=YES;
UITapGestureRecognizer*tap=[[UITapGestureRecognizeralloc]
initWithTarget:self
action:@selector(onTap)];
[self.descLabeladdGestureRecognizer:tap];

self.button=[UIButtonbuttonWithType:UIButtonTypeSystem];
[self.contentViewaddSubview:self.button];
[self.buttonsetTitle:@"我是cell的最后一个"forState:UIControlStateNormal];
[self.buttonsetBackgroundgreenColor]];
[self.buttonmas_makeConstraints:^(MASConstraintMaker*make){
make.left.mas_equalTo(15);
make.right.mas_equalTo(-15);
make.height.mas_equalTo(45);
make.top.mas_equalTo(self.descLabel.mas_bottom).offset(40);
}];

//必须加上这句
self.hyb_lastViewInCell=self.button;
self.hyb_bottomOffsetToCell=20;
self.isExpandedNow=YES;
}

returnself;
}

注意到这两行代码了吗:

self.hyb_lastViewInCell=self.button;
self.hyb_bottomOffsetToCell=20;

先是设置哪个视图作为cell的最后一个视图,然后设置了最后一个参考视图与cell的底部的距离。其中,self.hyb_lastViewInCell属性是必须要设置的,否则会抛出异常。

外部调用计算行高

在调用时,config传回来了cell对象,需要在调用处调用方法来配置好数据,才能正确地计算出cell的行高。通常是这样调用的:

-(CGFloat)tableView:(nonnullUITableView*)tableViewheightForRowAtIndexPath:(nonnullNSIndexPath*)indexPath{
HYBNewsModel*model=nil;
if(indexPath.row<self.dataSource.count){
model=[self.dataSourceobjectAtIndex:indexPath.row];
}

NSString*stateKey=nil;
if(model.isExpand){
stateKey=@"expanded";
}else{
stateKey=@"unexpanded";
}

return[HYBNewsCellhyb_heightForTableView:tableViewconfig:^(UITableViewCell*sourceCell){
HYBNewsCell*cell=(HYBNewsCell*)sourceCell;
//配置数据
[cellconfigCellWithModel:model];
}cache:^NSDictionary*{
return@{kHYBCacheUniqueKey:[NSStringstringWithFormat:@"%d",model.uid],
kHYBCacheStateKey:stateKey,
//如果设置为YES,若有缓存,则更新缓存,否则直接计算并缓存
//主要是对社交这种有动态评论等不同状态,高度也会不同的情况的处理
kHYBRecalculateForStateKey:@(NO)//标识不用重新更新
};
}];
}

外部显示cell

外部显示cell跟平时写的一样,没有什么特别要设置的:

-(nonnullUITableViewCell*)tableView:(nonnullUITableView*)tableView
cellForRowAtIndexPath:(nonnullNSIndexPath*)indexPath{
staticNSString*cellIdentifier=@"CellIdentifier";
HYBNewsCell*cell=[tableViewdequeueReusableCellWithIdentifier:cellIdentifier];

if(!cell){
cell=[[HYBNewsCellalloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier];

cell.selectionStyle=UITableViewCellSelectionStyleNone;
}

HYBNewsModel*model=nil;
if(indexPath.row<self.dataSource.count){
model=[self.dataSourceobjectAtIndex:indexPath.row];
}
[cellconfigCellWithModel:model];

cell.expandBlock=^(BOOLisExpand){
model.isExpand=isExpand;
[tableViewreloadRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
};

returncell;
}

温馨提示

对于UILabel类型,一定要设置属性preferredMaxLayoutWidth,否则在iOS6上会有问题,另外在设备6/6plus等上计算不准确。

设置preferredMaxLayoutWidth的值一定要与约束所计算出来的值一样,否则也会有问题。其实使用起来很简单的。

version 2.0

  • 本版本做了比较大的改动,为了提高计算行高的效率,降低消耗,使用了重用cell来计算行高的方式,因为计算行高时,永远只会创建一个。

  • 与version 1.0.0版本相比,API发生了些变化,原来参数中的indexPath改成了tableview

安装使用

这个组件是开源的,而且是支持cocoapods的,因此大家若是使用了cocoapods来管理项目第三方库,可以这样使用:

pod'HYBMasonryAutoCellHeight','~>2.0.0'

如果项目未使用cocoapods,直接下载源代码,然后将HYBMasonryAutoCellHeight文件夹拖入工程即可使用!

源代码

大家可以到github下载源代码来看看,内部实现很简单,当然要实现自动计算行高也是有系统方法的,不一定需要像笔者这样来实现。

下载源代码:HYBMasonryAutoCellHeight

最后

相信大家都明白一个道理,使用我自动化计算行高的方式方便我们开发,提高开发效率,但是会牺牲少许的性能。使用autolayout布局来计算行高,自然不会有纯代码计算行高的方式的性能高。大家在使用时,前期开发通常都会直接使用这种自动布局的方式来计算行高,因为大多数情况下,tableview展示的数据并不都是非常复杂的富文本、图片等数据,性能上没有什么问题。

像新浪微博这样的列表,自然要优化,那么更多的采用纯代码的方式来提前计算行高,并缓存起来,这样在滚动时直接使用行高(只是猜测)。

关键词:

猜您可能需要的服务: