根据文本数量更改UITableViewCell的高度

59

我需要能够调整我的UITableView中单个单元格的高度,以使其适应详细标签中的文本内容。

我尝试了以下代码,但它对我没有用:

如何在不使用自定义单元格的情况下换行UITableViewCell中的文本

尝试的代码:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
    cell.textLabel.numberOfLines = 0;
    cell.textLabel.font = [UIFont fontWithName:@"Helvetica" size:17.0];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellText = @"Go get some text for your cell.";
    UIFont *cellFont = [UIFont fontWithName:@"Helvetica" size:17.0];
    CGSize constraintSize = CGSizeMake(280.0f, MAXFLOAT);
    CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];

    return labelSize.height + 20;
}

这并没有起作用,它在单元格中显示了整个字符串,但是单元格的高度没有受到任何影响。


3
请提供您目前尝试过的代码。 - Manish Agrawal
添加的代码已经测试过,但是失败了。 - Josh Kahane
9个回答

83

很简单,只需将以下代码添加到您的程序中:

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

它会自动计算行高并返回一个浮点数。


1
它是否真的与heightForRowAtIndexPath一起工作?在我的测试中没有。另请参阅UITableView.h:“从tableView:heightForHeaderInSection:或tableView:heightForFooterInSection:返回此值会导致适合于tableView:titleForHeaderInSection:或tableView:titleForFooterInSection:返回的值的高度,如果标题不为nil。”我认为它只应该用于标题/页脚高度。 - Robert Kang
5
它可以工作,但仅适用于基本的“cell.textLabel”或其他来自Apple的选项。对于一些自定义单元格,可能会更难使用。 - stepik21
12
仅适用于标准单元格......无法用于我的自定义单元格。 - zumzum
3
对于我来说,我的自定义单元格可以工作,只需要添加您想要的约束即可使其生效。 - Fernando Mata
4
只有在函数"estimatedHeightForRowAtIndexPath"中提供了一个估计值,此方法才能完美运作。如果你的cell中有一个图片视图,并且其设置为"aspect fit",则此方法可能无法良好运作。请注意不要修改原文意思,仅让译文更通俗易懂。 - LuAndre
显示剩余4条评论

57

你好 Josh,

使用tableView:heightForRowAtIndexPath:可以在运行时为每个单元格指定大小。现在你的问题是如何从字符串中获取高度,NSString类中有一些函数可以通过这段代码解决你的问题:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
  NSString *str = [dataSourceArray objectAtIndex:indexPath.row];
    CGSize size = [str sizeWithFont:[UIFont fontWithName:@"Helvetica" size:17] constrainedToSize:CGSizeMake(280, 999) lineBreakMode:NSLineBreakByWordWrapping];
    NSLog(@"%f",size.height);
    return size.height + 10;
}

使用下面的代码可以将标签的行数设置为最大。因此,在cellForRowAtIndexPath:方法中设置它。

cell.textLabel.numberOfLines = 0;

如果你使用自定义单元格,那么需要管理所有标签的字符串并获取它们的总高度,然后再设置单元格的高度。

编辑: 从iOS 8开始,如果您为标签设置了正确的自动布局约束,则只需要设置以下委托方法即可实现此目的。

-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
   //minimum size of your cell, it should be single line of label if you are not clear min. then return UITableViewAutomaticDimension;    
   return UITableViewAutomaticDimension; 
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewAutomaticDimension;
}

就是这样,不需要进行任何计算。想了解更多信息,请查看此教程


dataSourceArray 保存了什么?我的文本吗? - Josh Kahane
@JoshKahane 是的,这是您的表格数据源数组,您可以从中提取表格标签。 - AJPatel
3
sizeWithFont已被废弃。 - Andrew
似乎在iOS 8.x和9.x中,当我为标签添加不同的字体大小(尺寸类)时,它们有不同的行为。在iOS 8.x中,单元格具有相同的高度,不考虑标签的字体大小(在iPad上字体更大,但单元格高度仍然相同)。 - Injectios
1
仅在estimatedHeightForRowAtIndexPathheightForRowAtIndexPath中添加UITableViewAutomaticDimension对于使用自定义样式的我有效。 :) - codelearner

51
在你的CustomCell中:记得为UILabel添加上下约束
要根据文本调整UILabel的高度,只需将UILabel的行数更改为0即可(在这里查看答案)。
然后在你的代码中,只需要设置两行。
self.tableView.estimatedRowHeight = 80;
self.tableView.rowHeight = UITableViewAutomaticDimension;

这是我的自定义单元格
在此输入图片描述 这是我的UILabel约束
在此输入图片描述
您将实现的屏幕

在此输入图片描述

=== 建议 ===
IF 您的单元格有一些UILabelsImages(不像我的示例)则:

  • 您应该将所有UILabelsImages放入一个GroupView(视图)中
  • 为此GroupView添加约束顶部和底部到超级视图(如我的图像中的UILabel)
  • 像上面我的建议一样调整UILabel高度
  • 根据内容(内容是全部UILabelsImages)调整GroupView高度
  • 最后,像上面的代码那样更改estimateRowHeighttableView.rowHeight

希望这可以帮助到您


如果一行中有一些UILabel和图像会发生什么? - Brave
@Brave 只需将 UILabelsImages 放入一个组视图 (View) 中。之后,您可以将该组视图视为一个 UILabel。按照我的指示配置约束并修改代码,我相信它会起作用。 - Linh
标签长度不同,图像大小也不同。在一行中,按照标签1、图像1、标签2、图像2的顺序排序。这样可以行得通吗? - Brave
当然可以实现^^。这是我的另一个问题,虽然它不是你的解决方案,但它包含了我已经实现的图像https://dev59.com/1ZXfa4cB1Zd3GeqPjb_Q - Linh
耶!谢谢。终于实现了iOS动态自定义单元格高度。 - myz
你好,你的代码非常有价值。谢谢你的分享。但是在我的情况下,由于设计要求,tableviewcell 有另一个 UIView,而且该 UIView 包含标签。我想根据标签的内容大小调整 tableviewcell 的大小,因为内容大小是动态的。请帮忙。 - Komal Gupta

23
根据您提供的代码,我认为您只增加了单元格高度而没有增加单元格文本标签(cell.textLabel)的高度。
理想情况下,您应该设置单元格文本标签和单元格的框架大小,以便在单元格中看到完整的文本。
查看视图大小问题的一个简洁方法是将其与背景颜色区分开来(尝试将cell.textLabel背景设置为黄色),然后查看高度是否实际上已经被设置。
以下是正确的实现方式。
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
    cell.textLabel.numberOfLines = 0;
    cell.textLabel.font = [UIFont fontWithName:@"Helvetica" size:17.0];

    NSString *cellText = @"Go get some text for your cell.";
    UIFont *cellFont = cell.textLabel.font;
    CGSize constraintSize = CGSizeMake(280.0f, MAXFLOAT);
    CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
    cell.textlabel.frame.size = labelSize; 
    cell.text = cellText;
}

希望这可以帮到你!

更新:这是一个相当古老的答案,其中许多行可能已经过时。


这就是你想要它做的对吧?我在想,无论你放入什么文本,单元格高度都没有增加。 - Nitin Alabur
起初看起来是那样的。我的下一个问题是,进入编辑模式后它被洗牌了。糟糕,好吧,我想我能解决这个问题,谢谢你帮我修复它! - Josh Kahane
1
可能可以在进入编辑模式后使用[tableView reloadData]。它可能会根据新的单元格框架重新计算。此外,在这种情况下,CGSize constraintSize = CGSizeMake(280.0f, MAXFLOAT); 可能会出现问题,因为您硬性设置了宽度为280.0f。 - Nitin Alabur
4
UILineBreakModeWordWrapеңЁiOS 6.0дёӯе·Іиў«ејғз”ЁпјҢиҜ·ж”№з”ЁNSLineBreakByWordWrappingгҖӮ - Ryan Wu
这样做不起作用,因为你只能使用tableView的rowHeight或heightForRowAtIndexPath来设置它。 - mskw
显示剩余5条评论

8

对于Swift开发者:

自定义单元格: 首先,您可以像下面这样计算文本的高度:

func calculateHeight(inString:String) -> CGFloat
    {
        let messageString = inString
        let attributes : [String : Any] = [NSFontAttributeName : UIFont.systemFont(ofSize: 15.0)]

        let attributedString : NSAttributedString = NSAttributedString(string: messageString, attributes: attributes)

        let rect : CGRect = attributedString.boundingRect(with: CGSize(width: 222.0, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, context: nil)

        let requredSize:CGRect = rect
        return requredSize.height
    }

设置文本标签的宽度

然后调用此函数:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        heightOfRow = self.calculateHeight(inString: conversations[indexPath.row].description)

        return (heightOfRow + 60.0)
}

对于基本单元格

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

这个函数不适用于自定义单元格.

希望它能正常工作。


2

您可以编写一个全局方法,以便在整个应用程序中使用。您需要根据自己的要求传递文本、字体和宽度。

在Swift 4中:

func heightForText(text: String,Font: UIFont,Width: CGFloat) -> CGFloat{

    let constrainedSize = CGSize.init(width:Width, height: CGFloat(MAXFLOAT))

    let attributesDictionary = NSDictionary.init(object: Font, forKey:NSAttributedStringKey.font as NSCopying)

    let mutablestring = NSAttributedString.init(string: text, attributes: attributesDictionary as? [NSAttributedStringKey : Any])

    var requiredHeight = mutablestring.boundingRect(with:constrainedSize, options: NSStringDrawingOptions.usesFontLeading.union(NSStringDrawingOptions.usesLineFragmentOrigin), context: nil)

    if requiredHeight.size.width > Width {
        requiredHeight = CGRect.init(x: 0, y: 0, width: Width, height: requiredHeight.height)

    }
    return requiredHeight.size.height;
}

2
tableView:heightForRowAtIndexPath:方法中,你可以使用sizeWithFont:constrainedToSize:来获取文本的大小。然后,只需返回高度加上一些额外的间距作为缓冲即可。

0
NSString *str;
NSArray* dictArr;

if (_index==0) {
    dictArr = mustangCarDetailDictArr[indexPath.section];

}

NSDictionary* dict = dictArr[indexPath.row];


if (indexPath.section ==0)
{

    str = [dict valueForKey:@"FeatureName"];
    if ([[dict valueForKey:@"FeatureDetail"] isKindOfClass:[NSString class]])
    {

        str = [dict valueForKey:@"FeatureDetail"];



    }
    else
    {
        if (dictArr.count>indexPath.row+1)
        {
            NSDictionary* dict2 = dictArr[indexPath.row+1];
            if ([[dict2 valueForKey:@"FeatureDetail"] isKindOfClass:[NSString class]])
            {


            }
        }

    }


}
CGSize size = [str sizeWithFont:[UIFont fontWithName:@"Helvetica" size:17] constrainedToSize:CGSizeMake(280, 999) lineBreakMode:NSLineBreakByWordWrapping];
NSLog(@"%f",size.height);
return size.height + 20;


}

0

我能够使用自动布局完成这个任务。确保您的标签与单元格的顶部和底部对齐(我正在使用原型单元格),并将其行数设置为0。然后在tableView:heightForRowAtIndexPath:sizeWithFont:constrainedToSize:中,您可以通过计算文本大小来设置单元格的高度:

NSString *key = self.detailContent.allKeys[indexPath.row];
NSDictionary *dictionary = self.detailContent[key];
NSString *cellText = dictionary[kSMDetailTableViewCellTextKey];
UIFont *cellFont = [UIFont fontWithName:kFontKeyEmondsans size:12.0];
CGSize constraintSize = CGSizeMake(252.0f, MAXFLOAT);
CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping];
return labelSize.height;// + 10;

tableView:heightForRowAtIndexPath:sizeWithFont:constrainedToSize: 这个方法属于哪个协议? tableView:heightForRowAtIndexPath: 属于 UITableViewDelegate 协议,但是 sizeWithFont 部分似乎不是来自苹果的 UITableView 协议。如果这是指的 UIKit 类别中的 NSString 的 sizeWithFont,那么它在 iOS 7 中已被弃用。 - stuckj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接