UITableViewCell的动态高度iOS

11

我在我的应用程序中使用自定义单元格实现了TableView,

我希望根据UITableViewCell中的文本长度动态设置行高,

这是Customcell的快照

: 这是我的UITableView的快照 heightForRowAtIndexPath的代码片段

#define FONT_SIZE 14.0f
#define CELL_CONTENT_WIDTH 320.0f
#define CELL_CONTENT_MARGIN 10.0f

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
    NSString *text = [DescArr objectAtIndex:[indexPath row]];
    CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
    CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
    CGFloat height = MAX(size.height, 100.0);
    return height; 
}

正如你在第二张图片中所看到的,单元格的高度是固定的,不会随着文本(内容)大小而改变。

我犯了什么错误?如何使标签或单元格根据其内容/文本更新其大小?


图片丢失了吗? :) - NHS
你的高度计算代码片段看起来正确,你是否正确设置了表视图的代理?同时尝试记录大小:NSLog(@"Hieght: %f", height); 看看高度是否正确。 - rckoenes
是的,我已经正确连接了委托,并且我的日志显示不同的高度为 54.036.018.0 - Krunal
1
CGFloat height = MAX(size.height, 100.0); 应该是100到55或默认单元格高度。 - SachinVsSachin
@Sachin:你的建议是正确的,将高度更改为55后,单元格高度适当,但标签未居中显示。当我在cellForRowAtIndexPath中记录我的单元格高度时,使用NSLog(@"cell.frame.size.height=%f",cell.frame.size.height); 在所有单元格中都显示高度为100 - Krunal
显示剩余3条评论
12个回答

13

请看这里 - 动态表格视图单元高度和自动布局教程。

所需条件:

  • 在单元格中的元素上设置必要的约束条件(确保所有操作都正确执行,否则可能会出现很多问题)。还要确保将IntrinsicSize设置为PlaceHolder值

enter image description here

  • 添加几个用于计算单元格大小的方法

方法:

//this will calculate required height for your cell
-(CGFloat)heightForBasicCellAtIndexPath:(NSIndexPath *)indexPath {
      static UIYourClassCellName *sizingCell = nil;
      //create just once per programm launching
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
      sizingCell = [self.tableView dequeueReusableCellWithIdentifier:@"identifierOfCell"];
});
  [self configureBasicCell:sizingCell atIndexPath:indexPath];
  return [self calculateHeightForConfiguredSizingCell:sizingCell];
}
//this method will calculate required height of cell
- (CGFloat)calculateHeightForConfiguredSizingCell:(UITableViewCell *)sizingCell {
      [sizingCell setNeedsLayout];
      [sizingCell layoutIfNeeded];
      CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
      return size.height;
}

并称之为

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
  return [self heightForBasicCellAtIndexPath:indexPath];
}

单元格配置

- (void)configureBasicCell:(RWBasicCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    //make some configuration for your cell
}

所有操作完成后,我获得了以下内容(单元格中的文本仅作为占位符):

enter image description here


谢谢,这是目前为止最好的解决方案!! - Stornu2
1
这是Swift 2.3的示例代码 https://github.com/dpakthakur/DynamicCellHeight - Deepak Thakur

6
以下代码对我来说运行良好。请尝试使用此代码。
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    CGFloat lRetval = 10;
    CGSize maximumLabelSize = CGSizeMake(231, FLT_MAX);
    CGSize expectedLabelSize;


    CGFloat numberoflines = [thirdcellText length]/17.0;

    if (indexPath.section == 0) {
        expectedLabelSize = [firstcellText sizeWithFont:[UIFont systemFontOfSize:16.0]
                                      constrainedToSize:maximumLabelSize
                                          lineBreakMode:NSLineBreakByWordWrapping];
        lRetval = expectedLabelSize.height;
    }
    else if(indexPath.section == 1)
    {
        expectedLabelSize = [secondcellText sizeWithFont:[UIFont systemFontOfSize:16.0]
                                       constrainedToSize:maximumLabelSize
                                           lineBreakMode:NSLineBreakByWordWrapping];
        lRetval = expectedLabelSize.height;
    }
    else if (indexPath.section == 2)
    {
        expectedLabelSize = [thirdcellText sizeWithFont:[UIFont systemFontOfSize:16.0]
                                       constrainedToSize:CGSizeMake(231, numberoflines*17.0)
                                           lineBreakMode:NSLineBreakByWordWrapping];
        lRetval = expectedLabelSize.height-128.0;
    }

    UIImage *factoryImage = [UIImage imageNamed:NSLocalizedString(@"barcode_factory_reset.png", @"")];

    CGFloat height = factoryImage.size.height;

    if (lRetval < height) {
        lRetval = height+15.0;
    }

    return lRetval;
}

尝试在您的自定义单元格类自动布局方法中添加以下代码。
textview.frame = frame;
CGRect frame1 = textview.frame;
frame1.size.height = textview.contentSize.height-2;
textview.frame = frame1;


textview.contentSize = CGSizeMake(textview.frame.size.width, textview.frame.size.height);

labelPtr.frame = CGRectMake(CGRectGetMinX(imageView.frame)+CGRectGetMaxX(imageView.frame)+5.0, textview.frame.size.height+10.0, 140, 16.0);
[labelPtr setNeedsDisplayInRect:labelPtr.frame];

尝试设置标签属性如下:
labelPtr = [[UILabel alloc] initWithFrame:CGRectZero];
labelPtr.backgroundColor =[UIColor clearColor];
[labelPtr setNeedsLayout];
[labelPtr setNeedsDisplay];
[self.contentView addSubview:labelPtr];

不用担心thirdcellText,它是一个包含文本的NSString对象。 - NHS
如果您有需要计算高度的文本,则可以检索并分配给thirdcellText。您只能在heightforrowatindexpath:方法中分配文本高度。 - NHS
如果您有用于添加文本的TextView,则上述代码将非常有用。 - NHS
我正在使用Label而不是TextView。 - Krunal
让我们在聊天中继续这个讨论。点击此处进入聊天室 - NHS
显示剩余2条评论

5

我看到了很多解决方案,但都是错误或不完整的。 您可以在viewDidLoad和自动布局中使用5行代码解决所有问题。 这是针对Objective-C的:

_tableView.delegate = self;
_tableView.dataSource = self;
self.tableView.estimatedRowHeight = 80;//the estimatedRowHeight but if is more this autoincremented with autolayout
self.tableView.rowHeight = UITableViewAutomaticDimension;
[self.tableView setNeedsLayout];
[self.tableView layoutIfNeeded];
self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0) ;

针对Swift 2.0:

 self.tableView.estimatedRowHeight = 80
 self.tableView.rowHeight = UITableViewAutomaticDimension      
 self.tableView.setNeedsLayout()
 self.tableView.layoutIfNeeded()
 self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0)

现在,您可以使用xib或在Storyboard中的tableview中创建单元格。这样,您就无需实现任何其他内容或覆盖。(不要忘记将行数设置为0),并将底部标签(constrain)的"Content Hugging Priority -- Vertical"降级为250。

enter image description here enter image description here

你可以在下面的链接中下载代码: https://github.com/jposes22/exampleTableCellCustomHeight 参考资料: http://candycode.io/automatically-resizing-uitableviewcells-with-dynamic-text-height-using-auto-layout/

我正在使用Swift,您的解决方案在支持iOS 9.0的设备上完美运行。但是,在运行它时,如果是iOS 7.1的设备,则单元格会变得不可见。@Jose Pose S,您能帮助我吗? - Cloy
非常抱歉,我无法为iOS 7提供帮助 :(,因为从iOS 8开始,自动布局已经发生了变化。您可以在Objective-C或Swift中使用它,但需要iOS 8或更高版本。 - Jose Pose S
这是Swift 2.3的示例代码 https://github.com/dpakthakur/DynamicCellHeight - Deepak Thakur
代码适用于所有版本的Swift和iOS 8或更高版本。 - Jose Pose S

5

我长期以来一直在寻找如何正确确定单元格高度的方法,而看起来最好的解决方案是使用 boundingRectWithSize 和 constrainedToSize 函数通常会错误地计算文本高度,您需要创建 UILabel 然后使用 sizeThatFits 函数,具体请参见以下内容:

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

    UILabel  * label = [[UILabel alloc] initWithFrame:CGRectMake(8, 5, celllabelWidth, 9999)];
    label.numberOfLines=0;
    label.font = [UIFont fontWithName:fontName size:textSize];
    label.text = @"celllabelTextHere";

    CGSize maximumLabelSize = CGSizeMake(celllabelWidth, 9999);
    CGSize expectedSize = [label sizeThatFits:maximumLabelSize];
    return expectedSize.height;
}

5

现在非常简单
按照以下步骤操作:

  1. 设置标签的约束(如果使用自定义单元格)
  2. 行数必须为0
  3. 设置UITableView的几个属性

self.tableView.estimatedRowHeight = 100.0;
self.tableView.rowHeight = UITableViewAutomaticDimension;

享受吧:)
更多详情请查看
www.raywenderlich.com
stackoverflow.com


这是Swift 2.3的示例代码 https://github.com/dpakthakur/DynamicCellHeight - Deepak Thakur

3

你可以尝试这个:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
     int topPadding = cell.yourLabel.frame.origin.x;
     int bottomPadding = cell.frame.size.heigth-(topPadding+cell.yourLabel.frame.size.height);
     NSString *text = [DescArr objectAtIndex:[indexPath row]];
     CGSize maximumSize = CGSizeMake(cell.yourLabel.frame.size.width, 9999);
     CGSize expectedSize = [text sizeWithFont:yourCell.yourLabel.font constrainedToSize:maximumSize lineBreakMode:yourCell.yourLabel.lineBreakMode];

     return topPadding+expectedSize.height+bottomPadding;
}

单元格文本被覆盖。 - Krunal
在.xib中,选择尺寸会动态变化的标签,在文件检查器下选择自动调整的所有内容。 - Engnyl

2
为了设置行高和预估行高的自动调整,请按照以下步骤实现单元格/行高布局的自动调整。
  • 分配和实现tableview的数据源和代理
  • UITableViewAutomaticDimension分配给rowHeight和estimatedRowHeight
  • 实现代理/数据源方法(例如heightForRowAt),并返回一个值UITableViewAutomaticDimension
@IBOutlet weak var table: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Don't forget to set dataSource and delegate for table
    table.dataSource = self
    table.delegate = self

    // Set automatic dimensions for row height
    // Swift 4.2 onwards
    table.rowHeight = UITableView.automaticDimension
    table.estimatedRowHeight = UITableView.automaticDimension


    // Swift 4.1 and below
    table.rowHeight = UITableViewAutomaticDimension
    table.estimatedRowHeight = UITableViewAutomaticDimension

}



// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    // Swift 4.2 onwards
    return UITableView.automaticDimension

    // Swift 4.1 and below
    return UITableViewAutomaticDimension
}

对于UITableviewCell中的标签实例

  • 将行数设置为0(并将换行模式设置为truncate tail)
  • 将所有约束条件(顶部、底部、右侧和左侧)设置为其父视图/单元格容器。
  • 可选项:如果您希望标签覆盖的垂直区域最小,即使没有数据,也可以设置标签的最小高度。

enter image description here


2
将英文翻译成中文:

参考使用自动布局的链接

否则,您可以使用以下方法

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {


NewsVCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

if (cell == nil)
{

    cell = [[NewsVCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];

}

cell.titleCell.numberOfLines = 0;
cell.descriptionCell.numberOfLines = 0;

cell.titleCell.font = [UIFont systemFontOfSize:12.0f];
cell.descriptionCell.font = [UIFont systemFontOfSize:12.0f];

cell.descriptionCell.textColor = [UIColor lightGrayColor];


CGSize maximumLabelSize;

if([UIDevice currentDevice].userInterfaceIdiom==UIUserInterfaceIdiomPad || [[[UIDevice currentDevice] model] isEqualToString:@"iPad Simulator"])
{
    maximumLabelSize = CGSizeMake(768, 10000);

}
else
{
    maximumLabelSize = CGSizeMake(270, 10000);

}

NSString *newsTitle =  [[feeds objectAtIndex:indexPath.row] objectForKey: @"title"];

NSString *descriptionsText = [[feeds objectAtIndex:indexPath.row] objectForKey: @"description"];


CGSize expectedTitleLabelSize = [newsTitle sizeWithFont: cell.titleCell.font constrainedToSize:maximumLabelSize lineBreakMode:cell.titleCell.lineBreakMode];

CGSize expectedDescriptionLabelSize = [descriptionsText sizeWithFont:cell.descriptionCell.font constrainedToSize:maximumLabelSize lineBreakMode:cell.descriptionCell.lineBreakMode];

NSLog(@"cellForRowAtIndexPath :indexpath.row %d: height expectedTitleLabelSize:%f , indexpath.row height expectedDescriptionLabelSize:%f",indexPath.row,expectedTitleLabelSize.height,expectedDescriptionLabelSize.height);



if (newsTitle.length > 0)
{

    cell.titleCell.frame = CGRectMake(20.0f, 10.0f, 270.0f ,expectedTitleLabelSize.height+20.0f);

}
else
{
     cell.titleCell.frame = CGRectMake(20.0f, 10.0f, 270.0f ,expectedTitleLabelSize.height-20.0f);
}


if (descriptionText.length > 0)
{
    cell.descriptionCell.frame =  CGRectMake(20.0f, 10.0f + cell.titleCell.frame.size.height, 270.0f, expectedDescriptionLabelSize.height+20.0f);

}
else
{
    cell.descriptionCell.frame =  CGRectMake(20.0f, cell.titleCell.frame.size.height, 270.0f, 0.0f);

}


  cell.descriptionCell.frame =  CGRectMake(20.0f, 10.0f + cell.titleCell.frame.size.height, 270.0f, expectedDescriptionLabelSize.height+20.0f);

cell.titleCell.text = newsTitle;
cell.descriptionCell.text = descriptionsText;

NSLog(@"indexpath.row %d :title %@ ",indexPath.row,newsTitle);

NSLog(@"indexpath.row %d :description %@",indexPath.row,descriptionsText);

return cell;

 }

pragma mark - UITableViewDelegate

   - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
 {
float totalHeight = 0.0f;

UILabel *labelTitle;


CGSize maximumLabelSize;


if([UIDevice currentDevice].userInterfaceIdiom==UIUserInterfaceIdiomPad || [[[UIDevice currentDevice] model] isEqualToString:@"iPad Simulator"])
{
    labelTitle = [[UILabel alloc]initWithFrame:CGRectMake(0.0f, 0.0f, 692.0f, 20.0f)];  // iPad
    maximumLabelSize = CGSizeMake(768.0f, 10000.0f);

}
else
{
    labelTitle = [[UILabel alloc]initWithFrame:CGRectMake(0.0f, 0.0f, 270.0f, 20.0f)];
    maximumLabelSize = CGSizeMake(270.0f, 10000.0f);

}



labelTitle.font = [UIFont systemFontOfSize:12.0f];


NSString *newsTitle;
NSString *newsDescription;

  //  cell.titleCell.text = [[feeds objectAtIndex:indexPath.row] objectForKey: @"title"];
  //   cell.descriptionCell.text = [[feeds objectAtIndex:indexPath.row] objectForKey: @"description"];



    newsTitle = [[feeds objectAtIndex:indexPath.row] objectForKey: @"title"];

    newsDescription = [[feeds objectAtIndex:indexPath.row] objectForKey: @"description"];

NSLog(@"indexpath.row %d :newsDescription.length %d",indexPath.row,newsDescription.length);
CGSize expectedTitleLabelSize;
CGSize expectedDescriptionLabelSize;


if (newsTitle.length > 0)
{
    expectedTitleLabelSize = [newsTitle sizeWithFont:labelTitle.font constrainedToSize:maximumLabelSize lineBreakMode:labelTitle.lineBreakMode];
    totalHeight = totalHeight + 20.0f;
}
else
{
    expectedTitleLabelSize = CGSizeMake(0.0f, 0.0f);
    totalHeight = -20.0f;
}

if (newsDescription.length > 0)
{
    expectedDescriptionLabelSize = [newsDescription sizeWithFont:labelTitle.font constrainedToSize:maximumLabelSize lineBreakMode:labelTitle.lineBreakMode];
    totalHeight = totalHeight + 20.0f;

}
else
{
    expectedDescriptionLabelSize = CGSizeMake(0.0f, 0.0f);
    totalHeight = -20.0f;
}


//  NSLog(@"question: %f title:%f",expectedQuestionLabelSize.height,expectedTitleLabelSize.height);

totalHeight = expectedDescriptionLabelSize.height + expectedTitleLabelSize.height + 30.0f+20.0f;




return totalHeight;

 }

1
如果您想将最大高度限制为100 pt,则必须使用MIN而不是MAX:
CGFloat height = fmin(size.height, 100.0);

0

试试这个,对我来说非常好用!

在viewDidLoad中写入以下代码:

-(void)viewDidLoad 
{
[super viewDidLoad];
 self.tableView.estimatedRowHeight = 100.0; // for example. Set your average height
 self.tableView.rowHeight = UITableViewAutomaticDimension;
}

在cellForRowAtIndexPath方法中编写以下代码:
 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
  static NSString *CellIdentifier = @"Cell";
  UITableViewCell *cell = [tableView 
  dequeueReusableCellWithIdentifier:CellIdentifier];
 if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
  }
    cell.textLabel.numberOfLines = 0; // Set label number of line to 0
    cell.textLabel.text=[[self.arForTable objectAtIndex:indexPath.row] valueForKey:@"menu"];
    [cell.textLabel sizeToFit]; //set size to fit 
    return cell;
 }

希望这能对某些人有所帮助。

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