使用Autolayout时UITableViewCell的高度计算

来源:互联网 发布:湖州公安网络报警网站 编辑:程序博客网 时间:2024/04/27 14:05

UITableViewCell的估算机制与高度计算  

估算机制

在iOS7及iOS7以下的系统中,当tableView要展示时,会调用代理的数据源方法- tableView: heightForRowAtIndexPath:(tableView获取高度默认访问rowHeight属性,实现了这个方法后,rowHeight属性就会失效,所以对于等高的cell来说, rowHeight能够减少许多不必要的计算和方法调用的开销)获得所有row的高度以确定scrollViewcontentSize.

  • - tableView: heightForRowAtIndexPath:适用于不等高cell(没实现该数据源方法就使用rowHeight属性值)
  • rowHeight适用于等高cell (rowHeight在iOS7中默认为44.f,iOS8为-1.f,即UITableViewAutomaticDimension)

以上两种用于计算cell的高度的方法,都是在tableView将要显示的时候,一次性计算出所有cell.这个时候,如果所展示的cell很多,并且每个cell的高度也很高,那么耗费在计算高度的初始时间将会多很多,所以苹果在iOS7的时候推出了estimatedRowHeight这个属性(与之类似的还有estimatedSectionHeaderHeight,estimatedSectionFooterHeight).

顾名思义,这个属性的意义在于估算.有了这个估算高度,就能确定contenSize啦,但是这个contenSize是个估算值,是通过estimatedRowHeightxcell的个数得到初始的contenSize中的高度,并不是最终的contenSize.实现了这个属性后,tableView就不会一次性计算所有的cell的高度了,只会计算当前屏幕能够显示的cell个数加上几个.滑动时,tableView不停地得到新的cell,调用数据源方法得到高度,更新自己的contenSize,在滑到最后的时候,会得到正确的contenSize,在这过程中,旁边的滚动条会不可避免地"抖动",因为contenSize在不停地更新.因此,在设置estimatedRowHeight时要给出尽量接近cell高度平均值的数值,让"抖动"更小.

// 从打印能看出,contentSize会按照一定的算法进行更新self.tableView.estimatedRowHeight = 100;- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    NSLog(@"%@",NSStringFromCGSize(tableView.contentSize));    return 300;}

此外,iOS7中每个cell的高度会被系统自动缓存起来,不会再重复计算了.

高度计算

在iOS7上,设置一个cell的尺寸有两种方式:

  1. AutoLayout
  2. Manual-sizing code (即人工手算)

第二种方式比较常见,通常我们通过在tableView: heightForRowAtIndexPath:方法中用cell对应的模型中的数据属性直接计算获得返回高度,在利用数据计算高度完成后 还可以将子控件的frame属性写入模型中,方便在模型中赋值布局子控件

其实第一种方式也很方便,最需要注意的是要设置好完整的约束.系统提供给了我们一个API叫- systemLayoutSizeFittingSize:,可以通过约束计算到cell的高度.

// 设置一个属性,或者是静态的全局变量的cell.因为这个cell是为了计算高度而生,不必每次调用方法都创建.@property (nonatomic, strong) XXXTableViewCell *prototypeCell; // 初始化时self.prototypeCell  = (XXXTableViewCell *)[self.tableView dequeueReusableCellWithIdentifier:@"XXXTableViewCell"];- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {   // 你或许会想到调用- tableView:cellForRowAtIndexPath方法拿到当前indexPath的cell,然后通过systemLayoutSizeFittingSize方法来计算高度.可是显示tableView之前只有拿到高度才能创建cell实例.如果在这里面调用该方法,会死循环.    XXXTableViewCell *cell = self.prototypeCell
//通过设置cell中的Model属性来计算高度并保存在模型的属性中    cell.model = [self.modelArray objectAtIndex:indexPath.row];     CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];  // 为什么要加上一个奇怪的数呢?  因为这里计算的只是cell的contentView的高度,分割线还占1个像素的高度.    return 1.0 / [UIScreen mainScreen].scale  + size.height; }
UITableViewCell的估算机制与高度计算 - lxl-霖 - lxl_霖的博客
 

另外需要注意的是,在iOS7下(iOS8没有这个问题),如果布局中有UILabel,并且行数大于0时,需要指定preferredMaxLayoutWidth,这样Label才能知道自己什么时候该换行,然后- systemLayoutSizeFittingSize才能得到正确的高度.

iOS8

自动算高

另外,self-sizing cell的另外一个重要功能就是实现了自动算高,不过需要满足2个条件:

  1. 使用Autolayout进行布局 
  2. 设置行高方式为自动计算 self.tableView.rowHeight = UITableViewAutomaticDimension
  3. 设置estimatedRowHeight的值self.tableView.estimatedRowHeight = 44

然后就OK了.

1.例如:

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

{


    ResultBalloonCell *cell = [ResultBalloonCellcellWithTableView:tableView];


 

    self.tableResult.rowHeight =UITableViewAutomaticDimension;

    self.tableResult.estimatedRowHeight = 100;

    cell.message = [self.translatedDataArrayobjectAtIndex:indexPath.row];

    

     CGFloat height3 = [cell.contentViewsystemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    

    [cell.contentViewsetNeedsLayout];

    [cell.contentViewlayoutIfNeeded];


    return (height3);


   


}


0 0