Iphone - 当每个单元格高度是动态时,何时计算tableview的heightForRowAtIndexPath?

Joh*_*ock 42 uitableview reloaddata ios heightforrowatindexpath

我已经多次看过这个问题,但令人惊讶的是,我没有看到一致的答案,所以我会自己尝试一下:

如果你有一个包含你自己的自定义UITableViewCells的tableview,它包含UITextViews和UILabels,其高度必须在运行时确定,你应该如何确定heightForRowAtIndexPath中每一行的高度?

最明显的第一个想法是通过计算并然后对cellForRowAtIndexPath内单元格内每个视图的高度求和来计算每个单元格的高度,并存储该最终总高度以供以后检索.

但这不起作用,因为cellForRowAtIndexPath被称为AFTER heightForRowAtIndexPath.

我唯一能想到的是在viewDidLoad中进行所有计算,然后创建所有UITableViewCells,计算单元格高度并将其存储在UITableViewCell子类内的自定义字段中,并将每个单元格放在NSMutableDictionary中,其中indexPath为键,然后使用cellForRowAtIndexPath和heightForRowAtIndexPath中的indexPath从字典中检索单元格,返回自定义高度值或单元格对象本身.

这种方法似乎是错误的,因为它没有使用dequeueReusableCellWithIdentifier,而是我将所有单元格一次加载到我的控制器中的字典中,并且委托方法只是从字典中检索正确的单元格.

我没有看到任何其他方法来做到这一点.这是一个坏主意 - 如果是这样,这样做的正确方法是什么?

Obl*_*ely 61

Apple实现UITableView的方式对每个人来说并不直观,而且很容易误解其作用heightForRowAtIndexPath:.一般意图是,这是一种更快,更轻松的内存方法,可以非常频繁地为表中的每一行调用.这与之相反,cellForRowAtIndexPath:通常较慢且占用内存较多,但仅在实际需要在任何给定时间显示的行中调用.

为什么Apple会像这样实现它?部分原因是它几乎总是更便宜(或者如果编码正确可以更便宜)来计算行的高度,而不是构建和填充整个单元格.鉴于在许多表中,每个单元的高度都是相同的,它通常要便宜得多.和的另一部分原因是因为iOS的需要知道整个表的大小:这允许它来创建滚动条,并设置它在滚动视图等.

因此,除非每个单元格的高度相同,否则在创建UITableView时,无论何时向其发送reloadData消息,都会为每个单元格的数据源发送一条heightForRowAtIndexPath消息.因此,如果您的表有30个单元格,则该消息将被发送30次.假设屏幕上只显示这30个单元格中的6个.在这种情况下,当创建它并发送reloadData消息时,UITableView将为每个可见行发送一个cellForRowAtIndexPath消息,即该消息被发送六次.

有些人有时会对如何在不创建视图的情况下计算单元格高度感到困惑.但通常这很容易做到.

例如,如果您的行高不同,因为它们包含不同数量的文本,您可以使用sizeWithFont:相关字符串上的某个方法来进行计算.这比构建视图然后测量结果更快.请注意,如果更改单元格的高度,则需要重新加载整个表格(使用reloadData - 这将询问代表的每个高度,但只询问可见的单元格)或选择性地重新加载大小所在的行改变了(上次我检查过时,也调用heightForRowAtIndexPath:了行,也进行了一些滚动工作以获得良好的测量).

看到这个问题,或许也是这个问题.

  • 但是,有一个问题:通常你必须知道你要给' - sizeWithFont:constrainedToSize:lineBreakMode:'的"宽度",以便计算单元格中包含的标签的正确高度,从而高度细胞本身.不幸的是当时调用表视图委托' - tableView:heightForRowAtIndexPath:'你没有包含在单元格内的标签的框架或边界,所以你必须"猜测"它们.如果您必须支持任何方向的iPhone,iPad以及混合类型(例如,披露或不披露等),这将变得特别复杂 (3认同)

lxt*_*lxt 10

所以,我认为你可以做到这一点,而不必一次创建你的细胞(正如你所说,这是浪费,也可能对大量细胞不切实际).

UIKit为NSString添加了几个方法,你可能已经错过了它们,因为它们不是主要的NSString文档的一部分.你感兴趣的是:

- (CGSize)sizeWithFont...
Run Code Online (Sandbox Code Playgroud)

这是Apple 文档的链接.

从理论上讲,这些NSString的添加存在于这个确切的问题:找出一块文本占用的大小而不需要加载视图本身.您可能已经可以访问每个单元格的文本作为表视图数据源的一部分.

我说'理论上'因为如果你在UITextView中进行格式化,你的里程可能因此解决方案而异.但是我希望它能让你至少在某个方面.Cocoa的一个例子就是我的女朋友.


Ken*_*ner 5

我过去使用的一种方法是创建一个类变量来保存您将在表中使用的单元实例(我将其称为原型单元格).然后在自定义单元格类中,我有一个方法来填充数据并确定单元格需要的高度.请注意,它可以是真正填充数据的方法的简单变体 - 而不是实际调整单元格中UILabel的大小,例如,它可以使用NSString高度方法来确定UILabel在最终单元格中的高度和然后使用总单元格高度(加上底部边框)和UILabel放置来确定实际高度.你只需要使用原型单元来了解元素的放置位置,这样你就可以知道当标签高达44个单位时它意味着什么.

heightForRow:我然后调用该方法返回高度.

cellForRow:我使用实际填充标签并调整它们大小的方法(您自己从不调整UITableView单元的大小).

如果你想得到花哨的话,你也可以根据传入的数据缓存每个单元格的高度(例如,如果确定高度,那么它可能只在一个NSString上).如果你有很多通常相同的数据,那么拥有一个永久缓存而不仅仅是内存是有意义的.

您也可以尝试根据字符或单词计数来估计行数,但根据我的经验,它永远不会起作用 - 当它出错时,它通常会弄乱一个单元格及其下面的所有单元格.


Wri*_*sCS 5

这是我根据UTextView中的文本量计算单元格高度的方法:

#define PADDING  21.0f

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

    if(indexPath.section == 0 && indexPath.row == 0)
    {   
        NSString *practiceText = [practiceItem objectForKey:@"Practice"];
        CGSize practiceSize = [practiceText sizeWithFont:[UIFont systemFontOfSize:14.0f] 
                   constrainedToSize:CGSizeMake(tblPractice.frame.size.width - PADDING * 3, 1000.0f)];
        return practiceSize.height + PADDING * 3;
    }

    return 72;
}
Run Code Online (Sandbox Code Playgroud)

当然,您需要调整PADDING其他变量以满足您的需要,但这UITextView会根据提供的文本量设置包含其中的单元格的高度.因此,如果只有3行文本,则单元格相当短,就好像有14行文本一样,单元格的高度相当大.


归档时间:

查看次数:

21635 次

最近记录:

6 年,6 月 前