当单元格构造不均匀时,如何计算heightForRowAtIndexPath?

时间:2011-03-14 03:12:22

标签: iphone ios uitableview heightforrowatindexpath

问题 - 如何在UITableViewController的“heightForRowAtIndexPath”方法中最好地计算行的高度,具体如下:

  1. 我正在使用自定义子类UITableViewCell&子视图(例如UILabels)的实际大小是在运行时计算的。依赖于诸如用户是否更改了字体大小的内容
  2. 在“heightForRowAtIndexPath”之前似乎没有准备好单元格,所以你不能依赖于调用你的特定自定义单元格即时查询它
  3. 目前我唯一想到的是:  1.在自定义UITableViewCell子类中创建一个方法来计算UITableViewCell子类中每个子视图(例如UILabel)的高度 - 然后在创建实例时在单元子类中使用它  2.同样在自定义子类中创建一个运行遍历所有UILabel的类方法,调用上述方法,总结高度,从而计算出总行高。它必须将数据传递给它(例如每个UILabels中的文本)  3.在UITableViewController“heightForRowAtIndexPath”中,您必须从上面的(2)调用“calRowHeight”类型方法,并将标签文本数据传递给它。因此,有效地调用自定义单元子类上的类方法,该方法知道如何计算总行高,但它使用的是与单元格所需的逻辑相同的...

    有没有比这更容易的方法?

2 个答案:

答案 0 :(得分:14)

创建UITableView时,无论何时向其发送reloadData消息,都会为每个单元格的数据源发送一条heightForRowAtIndexPath消息。因此,如果您的表有30个单元格,那么该消息将被发送30次。

假设屏幕上只显示这30个单元格中的6个。在这种情况下,当创建它并发送reloadData消息时,UITableView将为每个可见行发送一个cellForRowAtIndexPath消息,即该消息被发送六次。

为什么Apple会像这样实现它?部分原因是,计算行的高度几乎总是比构建和填充整个单元格更便宜。鉴于在许多表格中,每个单元格的高度都是相同的,它通常要便宜得多。部分原因是因为iOS需要知道整个表的大小:这允许它创建滚动条并将其设置在滚动视图等上。

如果您的行高不同,因为它们包含不同数量的文本,您可以使用相关字符串上的sizeWithFont:方法之一来进行计算。这比构建视图然后测量结果更快。请注意,如果更改单元格的高度,则需要重新加载整个表格(使用reloadData - 这将询问代表的每个高度,但只询问可见的单元格)或选择性地重新加载大小所在的行改变。

其他材料 如果我理解评论中的后续问题,以下内容可能有所帮助:

如果您正在实施编辑模式,那么需要更改表格行的高度并不罕见。例如,您可能在表行中有文本,当它们的单元格变窄时 - 为右侧的删除圆圈腾出空间 - 您可能希望某些单元格变得更高以容纳文本。这里的基本方法是:

  • 确保tableView:heightForRowAtIndexPath:方法知道您是否处于编辑模式。 (它可以使用isEditing询问tableView。)然后让方法返回正确的高度,具体取决于你是否处于编辑模式。

  • 在UITableViewController中的setEditing:animated:方法(或UIViewController中,无论你使用哪种 - 根据你使用的内容都有一些差异,所以值得仔细检查文档)向tableView发送reloadData消息在你改变它的状态之后。这将强制tableView获取每一行的高度,它将重新获取可见行的单元格。当您进入编辑模式时,tableView处理使单元格变窄,但如果您想在布局上做更多工作,请在tableView:cellForRowAtIndex:中执行此操作。如上所述,一般策略是找到一种快速计算高度的方法。使用文本sizeWithFont :(及其变体)可以做到这一点。如果您有图像等,那么您可以抓住它们的尺寸并做一些总和。

  • 除了这些步骤之外,您可能还希望在切换模式后稍微滚动tableView。如果行的高度不同,那么在切换模式后,您将在表中的错误位置结束。我在这里采用的方法是在我重新加载表以调用执行滚动调整的方法之后使用performSelector:withObject:afterDelay。您需要使用延迟,以便让tableView有时间收集新的高度和新的表格单元格。 (可能有一种更聪明的方法。)我做了一些总和来根据tableView的origin.y之间的差异进行滚动调整:cellForRowAtIndexPath:重新加载之前和之后屏幕上第一个可见行的单元格。因此,例如,要在预加载之前获得位置,有点像这样。

    CGPoint offset = [[self tableView] contentOffset];
    NSIndexPath* indexPath = [[self tableView] indexPathForRowAtPoint:CGPointMake(0,offset.y)];
    CGFloat preCellOffset = [[[self tableView] cellForRowAtIndexPath:indexPath] origin].y;
    

答案 1 :(得分:3)

我过去所做的事情,我不确定是最有效的,是来自我的heightForRowAtIndexPath方法调用cellForRowAtIndexPath,然后我要求查看该单元格的高度。我已经为页眉和页脚高度做了类似的事情。这样,如果我更改单元格,页眉或页脚,我不必记得去更新相应的高度方法。