2011-03-14 32 views
4

问题 - 怎样才能最好的计算高度的行中一个UITableViewController的“heightForRowAtIndexPath”的方法,因为:当单元格甚至没有构建时,我如何计算heightForRowAtIndexPath?

  1. 我使用的是子类的UITableViewCell &子视图的实际尺寸定制(如UILabels)在运行时计算&依赖于诸如用户是否更改字体大小等事情
  2. 单元格实际上并没有准备好它似乎在“heightForRowAtIndexPath”之前,因此您不能依靠调用您的特定自定义单元格即时查询

我现在唯一能想到的事情是: 1.在您的自定义UITableViewCell子类中,创建一个计算每个子视图高度的方法(例如, UILabel),它位于UITableViewCell子类中 - 然后在创建实例时在单元子类中使用它。 2.同样在自定义子类中,创建一个运行所有UILabel的类方法,调用上述方法,总结高度并因此计算出总行高度。它必须得到传递给它的数据(例如每个UILabels中的文本) 3.在UITableViewController“heightForRowAtIndexPath”中,您必须调用上面(2)中的“calRowHeight”类型方法,将标签文本数据。因此,有效地调用您的定制单元格子类中的类方法,该类方法知道如何计算出总行高度,但它使用的是与单元格相同的逻辑...

是否有比这更简单的方法我失踪?

+0

我已经在我的自定义的UITableViewCell子引入一个类的方法做到了这一点,正如你所提到的。它有效,但我也质疑效率。 – chris 2011-03-14 06:15:09

回答

14

当创建一个UITableView并且每当你发送一个reloadData消息时,数据源就会为每个单元发送一个heightForRowAtIndexPath消息。所以如果你的表格有30个单元格,那么这个消息会被发送30次。

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

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

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

其他材料 如果我理解在评论跟进的问题,以下可能会有帮助:

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

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

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

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

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

谢谢 - 重新您的最后一句话,为情景tableview进出编辑模式,我假设我会使用“layoutViews”方法 - 我还没有试图看看有没有办法从这个方法来设置自定义tableviewcell的行高? – Greg 2011-03-14 09:01:41

+0

感谢您的优秀更新 - 有趣的是,我采取了LavaSlider的建议,并在heightForRowAtIndexPath我(一)使用cellForRowAtIndexPath生成一个临时单元格,然后(b)调用layoutSubviews,使子视图设置。然后,我要采取由此产生的单元格视图大小,但这似乎并不奏效:(我提出了一个问题,在这个http://stackoverflow.com/questions/5304301/does-a-uitableviewcell-contentview-frame-size - 增加 - 自动添加后 – Greg 2011-03-14 23:08:07

+0

我推荐的方法是你在另一个问题中描述为“手动查看所有子视图(例如UILabels)并手动确定整体高度是多少”。知道你的单元格有多复杂,但根据我的经验,手动计算是相当简单的,它绝对是最高效的(更快,占用更少的内存) - 无论如何,获得工作解决方案的好运气我已经找到了自由日志在tableView委托/数据源方法帮助我了解什么时候被调用,什么取决于什么等等。 – Obliquely 2011-03-14 23:44:09

3

我过去所做的事情,我不确定是最有效的,是从我的heightForRowAtIndexPath方法调用cellForRowAtIndexPath,然后我问视图的单元格的高度。我为页眉和页脚高度做了类似的事情。这样,如果我更改单元格,页眉或页脚,我不必记得去更新相应的高度方法。

+0

多数民众赞成在有趣的 - 将有趣的听到,如果任何人支持这一点,或可以证实它不是一个有效的方法。我试图记住,如果heightForRowAtIndexPath被调用的只是有限数量的将要显示的单元格而不是所有单元格? (希望它会是前者) – Greg 2011-03-14 03:50:41

+0

它只能在屏幕上显示或部分显示单元格。在'cellForRowAtIndexPath'和'heightForRowAtIndexPath'中放置一个NSLog(),它报告行和部分,然后在它们被调用时观察。 – LavaSlider 2011-03-14 03:58:28

+0

是否会延迟将此标记为答案,直到我检查由cellForRowAtIndexPath生成的合成临时单元是否可以很容易地用于获取整体高度。请参阅问题我在这里http://stackoverflow.com/questions/5304301/does-a-uitableviewcell-contentview-frame-size-increase-automatically-after-adding – Greg 2011-03-14 23:09:37

相关问题