iOS中tableview是一个经常用的控件,尤其它的cell高度计算令人头疼。考虑到tableview的性能优化,我们一般都会在model封装时提前计算好cell的高度,代理返回cell高度时,拿到model,直接给它已计算好的高度。iOS8.0之后,可以使用AutoLayout结合tableview的属性让cell自己计算出高度。
使用步骤
- cell中使用Autolayout布局,例如这样:
cell高度=约束1的值+label1的高度+约束2的值+label2的高度+约束3的值
文字内容动态变化,那么label高度会动态变化,最终cell高度也会动态变化。 - 显设置tableview的属性:
//给tableview设置一个默认高度
self.tableView.estimatedRowHeight = 45;
//告诉tableview,cell是自适应的
self.tableView.rowHeight = UITableViewAutomaticDimension;
常遇问题
-
label的lines设置为1,label不能换行,高度始终是一行的高度,应该酌情设置,一般设置0即可,不限行高。
-
contentview的高度没有被子视图约束填充满。
-
label的宽度因为缺少约束而没法确定。
-
约束报错,列如:
因为bottom的约束值与实际的值不符,可以改变约束值,或者改变cell的高度
-
使用storyboard绘制的cell,Controller中注册了cell子类,导致绘制的cell显示不出来。
不需这样
// [self.tableView registerClass:NSClassFromString(@"MyTableViewCell1") forCellReuseIdentifier:cellId1];
// [self.tableView registerClass:NSClassFromString(@"MyTableViewCell2") forCellReuseIdentifier:cellId2];
直接这样即可
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row<self.data1.count) {
MyTableViewCell1 *cell = [tableView dequeueReusableCellWithIdentifier:cellId1 forIndexPath:indexPath];
cell.model=self.data1[indexPath.row];
return cell;
}else
{
MyTableViewCell2 *cell = [tableView dequeueReusableCellWithIdentifier:cellId2 forIndexPath:indexPath];
cell.model=self.data2[indexPath.row-self.data1.count];
return cell;
}
}
- cell的高度显示不正确,需要刷新下tableview,才会显示正确。那是因为cell中label的赋值是在layoutSubviews完成的。
-(void)layoutSubviews
{
[super layoutSubviews];
self.lbl.text=self.model.contentStr;
}
要么:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row<self.data1.count) {
MyTableViewCell1 *cell = [tableView dequeueReusableCellWithIdentifier:cellId1 forIndexPath:indexPath];
MyModel1 *model=self.data1[indexPath.row];
cell.lbl1.text=model.str1;
cell.lbl2.text=model.str2;
// cell.model=self.data1[indexPath.row];
return cell;
}else
{
MyTableViewCell2 *cell = [tableView dequeueReusableCellWithIdentifier:cellId2 forIndexPath:indexPath];
MyModel2 *model=self.data2[indexPath.row];
cell.lbl.text=model.contentStr;
// cell.model=self.data2[indexPath.row-self.data1.count];
return cell;
}
}
很多情况下我们还是希望赋值操作是在cell类中完成时,也可以这样:
- (void)showData
{
self.lbl1.text=self.model.str1;
self.lbl2.text=self.model.str2;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row<self.data1.count) {
MyTableViewCell1 *cell = [tableView dequeueReusableCellWithIdentifier:cellId1 forIndexPath:indexPath];
cell.model=self.data1[indexPath.row];
[cell showData];
return cell;
}else
{
MyTableViewCell2 *cell = [tableView dequeueReusableCellWithIdentifier:cellId2 forIndexPath:indexPath];
cell.model=self.data2[indexPath.row-self.data1.count];
[cell showData];
return cell;
}
}
进阶
假若label在contentview的多级子视图中也是可以实现cell高度自适应的。
原理也是同样的
demo效果
demo在这里