UITableView灵活/动态heightForRowAtIndexPath

Mar*_*ark 60 iphone uitableview

案件

通常,您将使用cellForRowAtIndexPath委托方法来设置您的单元格.为单元格设置的信息对于单元格的绘制方式以及大小的大小非常重要.

不幸的是,在heightForRowAtIndexPath委托方法之前调用cellForRowAtIndexPath委托方法,因此我们不能简单地告诉委托返回单元格的高度,因为那时它将为零.

因此,我们需要在表格中绘制单元格之前计算大小.幸运的是,有一种方法可以实现sizeWithFont,它属于NSString类.然而,存在问题,为了动态地计算正确的大小,它需要知道如何呈现单元中的元素.我将在一个例子中说明这一点:

想象一下UITableViewCell,它包含一个名为的标签textLabel.在cellForRowAtIndexPath我们放置的委托方法中textLabel.numberOfLines = 0,它基本上告诉标签它可以具有尽可能多的行以呈现特定宽度的文本.如果我们为textLabel提供一个大于最初赋予textLabel的宽度的文本,则会出现问题.第二行将出现,但单元格的高度不会自动调整,因此我们得到一个混乱的查看表视图.

正如前面所说的,我们可以用sizeWithFont计算出的高度,但它需要知道使用哪种字体,为,什么宽度等.如果,为了简单起见,我们只关心宽度,我们可以硬编码的宽度将约为320.0(不考虑填充).但是如果我们使用UITableViewStyleGrouped而不是普通的宽度那么将会发生大约300.0并且单元格将再次混乱.或者如果我们从纵向交换到横向,我们有更多的空间,但由于我们硬编码300.0,它将不会被使用.

在这种情况下,你必须问自己一个问题,你可以避免多少硬编码.

我自己的想法

您可以调用cellForRowAtIndexPath属于UITableView类的方法来获取特定节和行的单元格.我读了几篇帖子说你不想那样做,但我真的不明白.是的,我同意它已经分配了单元格,但heightForRowAtIndexPath委托方法只调用可见的单元格,因此无论如何都将分配单元格.如果正确使用,dequeueReusableCellWithIdentifier则不会在cellForRowAtIndexPath方法中再次分配单元格,而是使用指针并仅调整属性.那有什么问题呢?

请注意,单元格未在cellForRowAtIndexPath委托方法中绘制,当表格视图单元格变为可见时,脚本将调用setNeedDisplayUITableVieCell上的drawRect方法,该方法将触发绘制单元格的方法.所以cellForRowAtIndexPath直接调用代理不会失去性能,因为它需要被绘制两次.

好的,通过在cellForRowAtIndexPath委托方法中调用heightForRowAtIndexPath委托方法,我们可以获得有关单元格的所有信息,以确定它的大小.

也许你可以创建自己的sizeForCell方法来运行所有选项,如果单元格是Value1样式,或者Value2,等等.

结论/问题

这只是我在思想中描述的理论,我想知道我写的是不是正确的.或者也许还有另一种方法来完成同样的事情.请注意,我希望能够尽可能灵活地做事.

omz*_*omz 26

是的,我同意它已经分配了单元格,但是仅对可见的单元格调用heightForRowAtIndexPath委托方法,因此无论如何都将分配单元格.

这是不正确的.表视图需要为表视图中heightForRowAtIndexPath的所有行调用(如果已实现),而不仅仅是当前正在显示的行.原因是它需要计算出它的总高度才能显示正确的滚动指示器.


Jes*_*and 8

我曾经这样做过:

  1. 根据将用于表视图的集合对象创建集合对象(大小信息数组(字典,行高的NSNumber等).

  2. 当我们从本地或远程源处理数据时,就完成了这项工作.

  3. 当我创建这个集合对象时,我预先确定将要使用的字体的类型和大小.您甚至可以存储UIFont对象或用于表示内容的任何自定义对象.

  4. 每次实现UITableViewDataSource或UITableViewDelegate协议时,都会使用这些集合对象来确定UITableViewCell实例及其子视图的大小等.

通过这种方式,您可以避免必须继承UITableViewCell只是为了获得其内容的各种大小属性.

不要使用绝对值来初始化帧.使用基于当前方向和边界的相对值.

如果我们将它旋转到任何方向,只需在运行时执行调整大小机制.确保正确设置了autoresizingMask.

您只需要高度,UITableViewCell中不需要所有不必要的东西来确定行高.你可能甚至不需要宽度,因为我说宽度值应该相对于视图边界.


Eri*_*ric 7

这是我解决这个问题的方法

  1. 我假设在这个解决方案中只有一个Label具有"动态"高度
  2. 我还假设如果我们使标签自动尺寸拉伸高度,因为细胞增长只需更改细胞高度
  3. 我假设笔尖在标签所在的位置以及上方和下方有多少空间之间有适当的间距
  4. 每次我们更改笔尖中标签的字体或位置时,我们都不想更改代码

如何更新高度:

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

    // We want the UIFont to be the same as what is in the nib,
    //  but we dont want to call tableView dequeue a bunch because its slow. 
    //  If we make the font static and only load it once we can reuse it every
    //  time we get into this method
    static UIFont* dynamicTextFont;
    static CGRect textFrame;
    static CGFloat extraHeight;
    if( !dynamicTextFont ) {
        DetailCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
        dynamicTextFont = cell.resizeLabel.font;
        CGRect cellFrame = cell.frame;
        textFrame = cell.resizeLabel.frame;
        extraHeight = cellFrame.size.height-textFrame.size.height; // The space above and below the growing field
    }
    NSString* text = .... // Get this from the some object using indexPath 

    CGSize  size = [text sizeWithFont:dynamicTextFont constrainedToSize:CGSizeMake(textFrame.size.width, 200000.f) lineBreakMode:UILineBreakModeWordWrap];

    return size.height+extraHeight;
}
Run Code Online (Sandbox Code Playgroud)

问题:

  • 如果您没有使用原型单元格,则需要检查单元格是否为nil并初始化它
  • 您的笔尖/故事板必须具有UILabel自动调整大小并将多行设置为0