UITableView - 由单元格本身控制的动态单元格高度

Posted

技术标签:

【中文标题】UITableView - 由单元格本身控制的动态单元格高度【英文标题】:UITableView - dynamic cell height controlled by cell itself 【发布时间】:2012-01-24 00:10:55 【问题描述】:

我有以下设置:具有自定义 UITableViewCell 实现的 UITableView。在每个单元格中,我都有一个 UILabel 和一个 UIButton。首次显示表格时,在每个单元格中,UILabel 的行数设置为 1,并且所有单元格的高度都是固定的(在我的情况下为 60 像素)。当点击单元格中的按钮时,UILabel 的行数设置为 0 并开启自动换行,有效扩展表格单元格。

现在,问题是只有 UITableViewCell 的实现才知道标签是否展开 - 以及单元格高度应该是多少。但是所有者文件是表的数据源。

我不知道如何设置它。任何想法都表示赞赏。

更新这里是我的代码摘录

在自定义 UITableViewCell 实现中:

- (float)requiredHeight

    if(isFull)
    
        CGSize labelSize = [LblTitle.text sizeWithFont: [LblContent font]
                                     constrainedToSize: CGSizeMake(300.0f, 300.0f) 
                                         lineBreakMode: UILineBreakModeTailTruncation];
        return 42.0f + labelSize.height;
    
    else
    
        return 60.0f;
    

在所有者文件(UITableViewDelegate)中:

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

    OOCommentCell *cell = (OOCommentCell*)[tableView cellForRowAtIndexPath:indexPath];
    return [cell requiredHeight];

但是,这会随机导致无限循环或 BAD_ACCESS_EXCEPTION。

【问题讨论】:

【参考方案1】:

在您的表委托中实现方法UITableViewDelegate – tableView:heightForRowAtIndexPath:。如果您想在每个单元格的基础上定义高度,您可以通过在 tableView:heightForRowAtIndexPath 中调用您自己的 tableView:cellForRowAtIndexPath: 方法将此调用“转发”到单元格的类。

更新:在代码中实现。该错误是由调用 tableView:cellForRowAtIndexPath 的委托中的方法签名不正确引起的。

在自定义 UITableViewCell 实现中:

- (CGFloat)requiredHeight

    if(isFull)
    
        CGSize labelSize = [LblTitle.text sizeWithFont: [LblContent font]
                                     constrainedToSize: CGSizeMake(300.0f, 300.0f) 
                                         lineBreakMode: UILineBreakModeTailTruncation];
        return 42.0f + labelSize.height;
    
    else
    
        return 60.0f;
    

在所有者文件(UITableViewDelegate)中:

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

    OOCommentCell *cell = (OOCommentCell*)[self tableView:tableView cellForRowAtIndexPath:indexPath];
    return [cell requiredHeight];

【讨论】:

我认为我没有遵循您的逻辑。我已经定义了heightForRowAtIndexPath,在其中我尝试在 indexpath 中获取单元格,然后在其中调用一个方法以返回所需的路径,但这会导致 bad_access_exception。 基本上,表格是在询问 UITableViewDelegate,“X 行应该有多高?”通过方法 tableView:heightForRowAtIndexPath:。您应该返回所需高度(以像素为单位)的 CGFloat,而不是索引路径。 @JacobJinnings:您似乎误读了我的代码。对于“第 X 行应该有多高”,我试图获取第 X 行并询问它应该有多高 - 并返回该值。请仔细查看代码。【参考方案2】:

好的,经过一番挣扎,这就是我最终得到的,哪种有效。

    我创建了一个简单的类来包含与一个单元格相关的信息:
@interface CommentInfo : NSObject

    int ID;
    NSString *Name;
    NSString *Date;
    NSString *Content;
    BOOL IsFull;
    float Height;


@property (readonly) int ID;
@property (readonly) NSString *Name;
@property (readonly) NSString *Date;
@property (readonly) NSString *Content;
@property (readwrite, assign) float Height;
@property (readwrite, assign) BOOL IsFull;

- (id)initWithID:(int)_id withName:(NSString *)_name withDate:(NSString *)_date withText:(NSString *)_text;

@end

不要太担心所有属性 - 最重要的是Height

    在我的控制器(也是表视图的委托)中,我将数据保存为 NSMutableArray 指针,指向 CommentInfo 类型的对象。

    cellForRowAtIndexPath 中,我得到了相应的指针,并在构造过程中将其传递给自定义单元实现,并存储在那里。我还将self 设置为单元格的代表。

    在自定义单元格实现中,当我需要扩展/更改高度时,我会更新CommentInfo对象中的Height属性,并在委托中调用一个方法来更新显示。

    当这个updateDisplay方法被调用时,我简单的做如下:

[CommentsTable beginUpdates];
[CommentsTable endUpdates];
    heightForRowAtIndexPath 方法中,我检索到CommentInfo 的相应指针并读取Height 属性。由于控制器和单元格之间的指针相同,因此对该属性的任何更改都将在两个类中可见。

工作完成。

【讨论】:

我在 UITableViewCell 中使用 UIWebView,因此在调用 heightForRowAtIndexPath 时它无法判断高度。我所做的是将单元格设置为 UIWebView 的委托,并在 webViewDidFinishLoad 方法中调用 [webView sizeToFit]; webView.hidden = 否; [tableViewController setRowHeight:webView.bounds.size.height forRowId:id];在 UITableViewController 的 setRowHeight 方法中,我调用了您提供的这两个方法: [tableView beginUpdates]; [tableView endUpdates];它有效。

以上是关于UITableView - 由单元格本身控制的动态单元格高度的主要内容,如果未能解决你的问题,请参考以下文章

UITableViewCell 内 UITableView 的动态行高

当单元格高度为动态时设置 UITableView 的高度

如何更新动态生成的故事板中的自定义特定 UITableview 单元格?

涉及 JSON 解析以及静态和动态 UITableView 单元格的 Swift3 项目 - 使其更加面向对象

表格视图单元格高度动态 + 从 .xib 加载

UITableview 高度根据单元格设置