cell高度计算的多种方式

相关文推荐:
UITableView自动计算cell高度并缓存,无需再手动计算
四种方法实现UITableView的cell高度自动计算

第三方:
UITableView-FDTemplateLayoutCell使用教程详见README或者优化UITableViewCell高度计算的那些事

##cell的高度

cell的高度可以简单分为等高和不等高两大类。等高的情况不用多说,直接设置表视图的cellHeight的属性即可,所以这里只想聊聊不等高的情况。不等高的算法也可以分为两类:

#####一. 设置计算cell高度的辅助属性

最常见的是在模型里设置一个计算cell高度的辅助属性,然后重写这个属性的get方法,计算cell高度。

[^示例代码下载地址]:

HomeModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//HomeModel .h
#import <UIKit/UIKit.h>

@interface HomeModel : NSObject

@property (nonatomic,copy) NSString *icon; //图片
@property (nonatomic,copy) NSString *content; //内容的label
//单元格的高度
@property (nonatomic,assign) CGFloat cellHeight;

@end

//HomeModel.m
#import "HomeModel.h"
#import "HomeViewCell.h"

@implementation HomeModel

//惰性初始化是这样写的
-(CGFloat)cellHeight
{
//只在初始化的时候调用一次就Ok
if(!_cellHeight){
HomeViewCell *cell=[[HomeViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:homeIndentifier];
NSLog(@"我要计算高度");
// 调用cell的方法计算出高度
_cellHeight=[cell rowHeightWithCellModel:self];

}


return _cellHeight;
}

@end

HomeViewCell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//cell.h文件
#import <UIKit/UIKit.h>
#import "Masonry.h"

@class HomeModel;

static NSString *homeIndentifier=@"homeCell";

@interface HomeViewCell : UITableViewCell

//数据模型
@property (nonatomic,strong) HomeModel *homeModel;

//我们最后得到cell的高度的方法
-(CGFloat)rowHeightWithCellModel:(HomeModel *)homeModel;

@end

// cell.m文件

#import "HomeViewCell.h"
#import "HomeModel.h"

#define WS(weakSelf) __weak __typeof(&*self)weakSelf = self;

//头像的高度
#define iconH 80
#define iconW 100
//间距
#define marginW 10

@interface HomeViewCell ()

@property (nonatomic,weak) UIImageView *icon; //头像
@property (nonatomic,weak) UILabel *content; //显示文本的label
@property (nonatomic,weak) UIImageView *line; //下划线

//定义一个contentLabel文本高度的属性
@property (nonatomic,assign) CGFloat contentLabelH;

@end

@implementation HomeViewCell

-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self=[super initWithStyle:style reuseIdentifier:reuseIdentifier];
if(self){
//1.添加子控件
[self setupUI];

}
return self;
}

#pragma mark 添加子控件
-(void)setupUI
{
//1.添加图片
UIImageView *icon=[UIImageView new];
icon.contentMode=UIViewContentModeScaleAspectFill;
icon.clipsToBounds=YES;
[self.contentView addSubview:icon];
self.icon=icon;
//2.添加label
UILabel *content=[UILabel new];
content.numberOfLines=0; //多行显示
content.font=[UIFont systemFontOfSize:16];
[self.contentView addSubview:content];
self.content=content;
//3.底部添加一条线
UIImageView *line=[UIImageView new];
line.backgroundColor=[UIColor grayColor];
[self.contentView addSubview:line];
self.line=line;

//设置约束
__weak __typeof(&*self)weakSelf = self;
//1.设置图片的大小
[self.icon mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(iconH); //头像的高度
make.width.mas_equalTo(iconW); //头像的宽度
make.top.equalTo(weakSelf.mas_top).offset(marginW) ; //距离顶部10的距离
make.centerX.equalTo(weakSelf.mas_centerX); //头像的中心x和cell的中心x一样

// make.centerY.equalTo(self.mas_centerY); 头像的中心y和cell的中心y一样
}];
//2.设置contentLabel
[self.content mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(weakSelf.icon.mas_bottom).offset(marginW); //文本距离头像底部10个间距
make.left.equalTo(weakSelf.mas_left).offset(marginW); //文本距离左边的距离
make.right.equalTo(weakSelf.mas_right).offset(-marginW); //文本距离右边的距离

//文本高度 我们再得到模型的时候 在传递
}];


//3.设置下划线的大小
[self.line mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(0.5);
make.left.equalTo(weakSelf.mas_left).offset(0);
make.right.equalTo(weakSelf.mas_right).offset(0);
make.bottom.equalTo(weakSelf.mas_bottom).offset(-marginW); //下划线距离底部10的距离
}];

}

//传递数据模型
-(void)setHomeModel:(HomeModel *)homeModel
{
_homeModel=homeModel;

self.icon.image=[UIImage imageNamed:homeModel.icon]; //头像
self.content.text=homeModel.content; //文本内容
}

//在表格cell中 计算出高度
-(CGFloat)rowHeightWithCellModel:(HomeModel *)homeModel
{
_homeModel=homeModel;
__weak __typeof(&*self)weakSelf = self;
//设置标签的高度
[self.content mas_makeConstraints:^(MASConstraintMaker *make) {
// weakSelf.contentLabelH 这个会调用下面的懒加载方法
make.height.mas_equalTo(weakSelf.contentLabelH);
}];

// 2. 更新约束
[self layoutIfNeeded];

//3. 视图的最大 Y 值
CGFloat h= CGRectGetMaxY(self.content.frame);

return h+marginW; //最大的高度+10
}

/*
* 懒加载的方法返回contentLabel的高度 (只会调用一次)
*/
-(CGFloat)contentLabelH
{
if(!_contentLabelH){
CGFloat h=[self.homeModel.content boundingRectWithSize:CGSizeMake(([UIScreen mainScreen].bounds.size.width)-2*marginW, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16]} context:nil].size.height;

_contentLabelH=h+marginW; //内容距离底部下划线10的距离
}
return _contentLabelH;
}



@end

HomeViewController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//HomeViewController.h
#import <UIKit/UIKit.h>

@interface HomeViewController : UITableViewController

@end

//HomeViewController.m
#import "HomeViewController.h"
#import "HomeViewCell.h"
#import "HomeModel.h"

@interface HomeViewController ()

@property (nonatomic,strong) NSMutableArray *arr; //存放的我们自定义的数据
@property (nonatomic,strong) NSMutableArray *arrModel; //存放的数据模型

@end

@implementation HomeViewController

-(NSMutableArray *)arr
{
if(_arr==nil){
_arr=[NSMutableArray array];
[_arr addObject:@"高通与小米达成专利授权协议的主要影响在于小米的海外市场,因为在国内小米并不会遇到专利问题。然而,分析小米在海外遇到的问题会发现,这远不是签订一个专利协议能解决"];
[_arr addObject:@"当年科比和乔丹的对决,那时的科比几乎无所不能,谁又会想到他会退役,说不定再过10年,我也就退役了。"];
[_arr addObject:@"高通与小米达成专利授权协议的主要影响在于小米的海外市场,因为在国内小米并不会遇到专利问题。然而,分析小米在海外遇到的问题会发现,这远不是签订一个专利协议能解决"];
[_arr addObject:@"hello 这是我的iOS学习群 519797474,欢迎加入"];
[_arr addObject:@"佛堂中,大师正在对弟子讲话:“为师为你们所起之名并非随随便便,而是为师对你们的期望,你们懂了吗?”众弟子都回答懂了。只有一名弟子默然不语。大师见状,问那名弟子道:“圆寂,你为什么不说话?"];
[_arr addObject:@"最后这个例子是老例子了最后这个例子是老例子了,我想给大家看看其实Masonry做动画也和其他的Autolayout方法一样,但是添加约束的代码却非常的少最后这个例子是老例子了,我想给大家看看其实Masonry做动画也和其他的Autolayout方法一样,但是添加约束的代码却非常的少最后这个例子是老例子了,我想给大家看看其实Masonry做动画也和其他的Autolayout方法一样,但是添加约束的代码却非常的少最后这个例子是老例子了,我想给大家看看其实Masonry做动画也和其他的Autolayout方法一样,但是添加约束的代码却非常的少最后这个例子是老例子了,我想给大家看看其实Masonry做动画也和其他的Autolayout方法一样,但是添加约束的代码却非常的少最后这个例子是老例子了,我想给大家看看其实Masonry做动画也和其他的Autolayout方法一样,但是添加约束的代码却非常的少"];
[_arr addObject:@"今天和老婆吵架,吵到激烈的时候,我突然觉得我一个大男人为什么要和一个女人一般见识呢?何况还是自己的老婆!当时我就跟老婆道了歉,老婆挺高兴的.道完歉,她哥哥把菜刀放下了,她弟弟把铁锹也放下了,她妹妹拽着我头发的手也松开了,妹夫手里的擀面杖也扔地下了,老丈人也把砖头丢开了;"];
[_arr addObject:@"昨天去一家工厂面试监工,给出的工资太低,简直不能忍。最后跟主管去车间看了看,我觉得工资只是数字而已,关键是学习的机会,所以留下来了。"];
[_arr addObject:@"大家好,我是他主治医生。请原谅他,他因为神经病引起的并发症迷恋上了装逼,去年高考 ,他差一点就上清华了,现在想来依然倍感惋惜,清华分数695,他考了69.5,就差那么一点。巨大的打击彻底粉碎了他对未来的憧憬,整日在家自暴自弃专研怎么装逼,终成为新一代装逼大师,将装逼 方法研究的出神入化,各种装逼方法,无死角装逼,终于横空出世…。你看,他又在装逼......."];
[_arr addObject:@"高通与小米达成专利授权协议的主要影响在于小米的海外市场,因为在国内小米并不会遇到专利问题。然而,分析小米在海外遇到的问题会发现,这远不是签订一个专利协议能解决,周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工"];
[_arr addObject:@"很多时候我们过高估计了机遇的力量,低估了规划的重要性,不明确的乐观主义者只知道未来越来越好,却不知道究竟多好,因此不去制定具体计划。他想在未来获利,但是却认为没有必要制定具体规划。"];
[_arr addObject:@"hello 这是我的iOS学习群 519797474,欢迎加入"];
for(int i=0;i<_arr.count;i++){
HomeModel *m=[[HomeModel alloc]init];
m.icon=[NSString stringWithFormat:@"%i",i];
m.content=_arr[i];
//把模型那存到模型数组中
[self.arrModel addObject:m];

}

}
return _arr;
}

-(NSMutableArray *)arrModel
{
if(_arrModel==nil){
_arrModel=[NSMutableArray array];
}
return _arrModel;
}

- (void)viewDidLoad {
[super viewDidLoad];

self.tableView.separatorStyle=UITableViewCellSeparatorStyleNone;//去掉默认下划线
self.tableView.estimatedRowHeight=200; //预估行高 可以提高性能
self.tableView.rowHeight = 88;

//注册表格单元
[self.tableView registerClass:[HomeViewCell class] forCellReuseIdentifier:homeIndentifier];

}


/*
返回多少行
*/
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//因为是我们自定义的数据 所以 这里写arr而不是arrModel 因为只有这样才会调用arr的懒加载犯法
return self.arr.count;
}

/*
返回表格单元
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//取出模型
HomeModel *model=self.arrModel[indexPath.row];

HomeViewCell *cell = [tableView dequeueReusableCellWithIdentifier:homeIndentifier];

//传递模型给cell
cell.homeModel=model;

return cell;
}

/*
* 返回每一个表格单元的高度
*/

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{


//取出模型
HomeModel *homeModel=self.arrModel[indexPath.row];

return homeModel.cellHeight ;
}




@end

#####二. 自动布局计算cell高度

上面的方法相对麻烦一些,好消息是iOS8以后,苹果提供了一个自动计算cell高度的方法,也就是本文要介绍的方法。
利用自动布局计算cell高度

首先我们要了解的是在xib,或storyBoard里面UILabel,UIButton等控件的的尺寸是可以随着内容的变化而自动变化的,也就是说你给一个label添加好位置约束后,它的尺寸就可以不添加任何约束。
让自动适应内容的子控件与cell建立联系。例如,一个label通过添加约束使它距左边,上边的距离以及宽度已经确定,此时再让label的底部与父控件的底部建立约束关系(注意label的numberOfLines应该设置为0,要不然label不会自动换行)。

添加计算cell估算高度的代码和cell高度的代码

1
2
self.tableView.estimatedRowHeight = 44;
self.tableView.rowHeight = UITableViewAutomaticDimension;

总结: 其实用autoLayout自动计算cell高度可以分为三步:

  • 让子控件和父控件建立联系。

  • 添加cell的估算高度。

  • 添加cell的高度。

    另外,这个方法只试用在iOS8以后,iOS8之前的系统不支持,然而可喜的消息是在今年3月的苹果发布会上,说到iOS9的普及率已经达到了80%,想必iOS8的普及率在90%应该没有什么问题。