基于内容的动态UITableView单元格高度

时间:2012-04-23 19:53:50

标签: ios iphone objective-c uitableview

我有一个UITableView,其中填充了自定义单元格(继承自UITableViewCell),每个单元格都包含一个UIWebView,根据其内容自动调整大小。这就是问题,如何根据内容(变量UITableView)更改webView单元格的高度。

解决方案必须是动态的,因为用于填充UIWebViews的HTML是从不断变化的Feed中解析的。

我觉得我需要使用UITableView委托方法heightForRowAtIndexPath但是从它的定义:

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ;//This needs to be variable
}

我无法访问单元格或其内容。我可以在cellForRowAtIndexPath

中更改单元格的高度

任何帮助都会很棒。感谢。

注意

我在2年前问过这个问题。通过自动布局的介绍,可以找到iOS7的最佳解决方案:

Using Auto Layout in UITableView for dynamic cell layouts & variable row heights

在iOS8上,此功能内置于SDK

10 个答案:

答案 0 :(得分:24)

这通常效果很好:

目标-C:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewAutomaticDimension;
}

夫特:

override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
    return UITableViewAutomaticDimension;
}

答案 1 :(得分:20)

我发现动态高度的最佳方法是预先计算高度并将其存储在某种类型的集合中(可能是数组)。假设单元格主要包含文本,则可以使用-[NSString sizeWithFont:constrainedToSize:lineBreakMode:]计算高度,然后返回heightForRowAtIndexPath:

中的相应值

如果内容不断变化,您可以实现一种方法,在提供新数据时更新高度数组。

答案 2 :(得分:6)

self.tblVIew.estimatedRowHeight = 500.0; // put max you expect here.
self.tblVIew.rowHeight = UITableViewAutomaticDimension;

答案 3 :(得分:5)

我尝试了很多解决方案,但有一个解决方案就是这个,由朋友建议:

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

    int height = [StringUtils findHeightForText:yourLabel havingWidth:yourWidth andFont:[UIFont systemFontOfSize:17.0f]];

    height += [StringUtils findHeightForText:yourOtherLabel havingWidth:yourWidth andFont:[UIFont systemFontOfSize:14.0f]];

    return height + CELL_SIZE_WITHOUT_LABELS; //important to know the size of your custom cell without the height of the variable labels
}

StringUtils.h类:

#import <Foundation/Foundation.h>

@interface StringUtils : NSObject

+ (CGFloat)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font;

@end

StringUtils.m class:

#import "StringUtils.h"

@implementation StringUtils

+ (CGFloat)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font {
    CGFloat result = font.pointSize+4;
    if (text) {
        CGSize size;

        CGRect frame = [text boundingRectWithSize:CGSizeMake(widthValue, CGFLOAT_MAX)
                                          options:NSStringDrawingUsesLineFragmentOrigin
                                       attributes:@{NSFontAttributeName:font}
                                          context:nil];
        size = CGSizeMake(frame.size.width, frame.size.height+1);
        result = MAX(size.height, result); //At least one row
    }
    return result;
}

@end

它对我来说很完美。我有一个自定义单元格,其中包含3个固定尺寸的图像,2个固定尺寸的标签和2个可变标签。

答案 4 :(得分:3)

这是我从twitter获取推文然后将它们存储在CoreData中以供离线阅读时用于动态单元格高度的代码。

这不仅展示了如何获取单元格和数据内容,还展示了如何使用填充动态地将UILabel大小调整为内容

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

    Tweet *tweet = [self.fetchedResultsController objectAtIndexPath:indexPath];

    NSString* text = tweet.Text;

    TweetTableViewCell *cell = (TweetTableViewCell*)[self tableView:tableView cellForRowAtIndexPath:indexPath];

    //Set the maximum size
    CGSize maximumLabelSize = cell.tweetLabel.frame.size;
    CGPoint originalLocation = cell.tweetLabel.frame.origin;

    //Calculate the new size based on the text
    CGSize expectedLabelSize = [text sizeWithFont:cell.tweetLabel.font constrainedToSize:maximumLabelSize lineBreakMode:cell.tweetLabel.lineBreakMode];


    //Dynamically figure out the padding for the cell
    CGFloat topPadding = cell.tweetLabel.frame.origin.y - cell.frame.origin.y;


    CGFloat bottomOfLabel = cell.tweetLabel.frame.origin.y + cell.tweetLabel.frame.size.height;
    CGFloat bottomPadding = cell.frame.size.height - bottomOfLabel;


    CGFloat padding = topPadding + bottomPadding;


    CGFloat topPaddingForImage = cell.profileImage.frame.origin.y - cell.frame.origin.y;
    CGFloat minimumHeight = cell.profileImage.frame.size.height + topPaddingForImage + bottomPadding;

    //adjust to the new size
    cell.tweetLabel.frame = CGRectMake(originalLocation.x, originalLocation.y, cell.tweetLabel.frame.size.width, expectedLabelSize.height);


    CGFloat cellHeight = expectedLabelSize.height + padding;

    if (cellHeight < minimumHeight) {

        cellHeight = minimumHeight;
    }

    return cellHeight;
}

答案 5 :(得分:3)

我认为这样的算法也适合你:

1)在cellForrowAtIndexPath中激活你的webview进行加载,并为它们提供等于indexPath.row的标签

2)在webViewDidFinishLoading中,您计算​​单元格中内容的高度,并使用键和值组成一个字典,如下所示:key = indexPath.row value = height

3)调用[tableview reloadData]

cellForRowAtIndexPath:indexPath]中的

4)为相应的单元格设置适当的高度

答案 6 :(得分:3)

iOS中具有动态高度的单元格的一个大问题是表格vc必须在绘制单元格之前计算并返回每个单元格的高度。但是,在绘制单元格之前,它没有框架,因此没有宽度。如果您的单元格要根据textLabel中的文本数量更改其高度,则会导致问题,因为您不知道其宽度。

我见过的常见解决方案是人们为单元格宽度定义数值。这是一种糟糕的方法,因为表可以是普通的或分组的,使用iOS 7或iOS 6样式,在iPhone或iPad上显示,以横向或纵向模式等。

我在我的iOS应用程序中遇到了这些问题,它支持iOS5 +以及具有多种方向的iPhone和iPad。我需要一种方便的方法来自动执行此操作并将逻辑从视图控制器中移除。结果变成了一个UITableViewController子类(因此它可以保持状态),它支持默认单元格(默认和字幕样式)以及自定义单元格。

你可以在GitHub(https://github.com/danielsaidi/AutoSizeTableView)抓住它。我希望它能帮助那些仍在努力解决这个问题的人。如果你确实检查出来,我很想听听你的想法,以及它是否适合你。

答案 7 :(得分:1)

这是我很好的解决方案之一。它对我有用。

vimbuffs = a07f233d

我们需要应用这两项更改。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    cell.textLabel.text = [_nameArray objectAtIndex:indexPath.row];
    cell.textLabel.numberOfLines = 0;
    cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewAutomaticDimension;
}

答案 8 :(得分:0)

夫特 使用自定义单元格和标签。设置UILabel的约束。 (上,左,下,右)将UILabel的行设置为0

在ViewController的viewDidLoad方法中添加以下代码:

a: first
c:
  e:
    g: fifth
    f: fourth
  d: third
b: second

a: first
c:
  e:
    g: fifth
    f: fourth
  d: third
b: second

//代表&amp;数据来源

tableView.estimatedRowHeight = 68.0
tableView.rowHeight = UITableViewAutomaticDimension

答案 9 :(得分:0)

在Swift 4+中,您可以将其设置为动态

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableView.automaticDimension
}