26

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

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

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

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

我无法访问单元格或其内容。我可以更改单元格的高度cellForRowAtIndexPath吗?

任何帮助都会很重要。谢谢。

笔记

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

在 UITableView 中使用自动布局进行动态单元格布局和可变行高

在 iOS8 上,此功能内置在 SDK 中

4

12 回答 12

29

这通常工作得很好:

目标-C:

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

迅速:

override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
    return UITableViewAutomaticDimension;
}
于 2014-06-17T19:20:43.063 回答
20

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

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

于 2012-04-23T20:02:33.117 回答
6
self.tblVIew.estimatedRowHeight = 500.0; // put max you expect here.
self.tblVIew.rowHeight = UITableViewAutomaticDimension;
于 2015-11-19T12:55:30.640 回答
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 类:

#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 个可变标签。

于 2014-05-13T16:15:33.340 回答
4

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

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

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

您可以在 GitHub ( https://github.com/danielsaidi/AutoSizeTableView ) 上获取它。我希望它可以帮助那些仍在为这个问题苦苦挣扎的人。如果您确实检查了它,我很想听听您的想法以及它是否适合您。

于 2014-02-20T22:57:17.627 回答
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;
}
于 2012-04-23T20:02:55.257 回答
2

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

1)在 cellForrowAtIndexPath 你激活你的 webviews 加载并给他们标签等于 indexPath.row

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

3)调用[tableview reloadData]

4) 在 [tableview cellForRowAtIndexPath:indexPath] 中为相应的单元格设置适当的高度

于 2012-04-23T20:09:39.630 回答
1

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

- (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;
}

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

1)cell.textLabel.numberOfLines = 0;
  cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;

2)return UITableViewAutomaticDimension;
于 2018-03-08T05:21:55.683 回答
1

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

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableView.automaticDimension
}
于 2019-03-12T12:21:07.657 回答
0

我总是在超级单元类中的所有单元中实现这一点,因为由于某种原因UITableViewAutomaticDimension不能很好地工作。

-(CGFloat)cellHeightWithData:(id)data{
    CGFloat height = [[self contentView] systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
    [self fillCellWithData:data]; //set the label's text or anything that may affect the size of the cell
    [self layoutIfNeeded];
    height = [[self contentView] systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
    return height+1; //must add one because of the cell separator
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath只需在您使用虚拟单元格时调用此方法即可。

注意:这仅适用于自动布局,但也适用于 ios 7 及更高版本。

pd:不要忘记检查 xib 或情节提要上的“首选宽度显式”复选框并设置静态宽度(在cmd + alt + 5菜单上)

于 2015-08-24T17:30:27.510 回答
0

Swift 使用自定义单元格和标签。为 UILabel 设置约束。(top, left, bottom, right) 将 UILabel 的行设置为 0

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

tableView.estimatedRowHeight = 68.0
tableView.rowHeight = UITableViewAutomaticDimension

// 委托和数据源

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension;
}
于 2017-02-25T08:41:16.610 回答
0

我在 UILabel 进行了非常大的测试。最重要的是无法工作,然后我为字符串创建了如下类别并获得了确切的高度

- (CGFloat)heightStringWithEmojifontType:(UIFont *)uiFont ForWidth:(CGFloat)width {

// Get text
CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), (CFStringRef) self );
CFIndex stringLength = CFStringGetLength((CFStringRef) attrString);

// Change font
CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef) uiFont.fontName, uiFont.pointSize, NULL);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, stringLength), kCTFontAttributeName, ctFont);

// Calc the size
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString);
CFRange fitRange;
CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(width, CGFLOAT_MAX), &fitRange);

CFRelease(ctFont);
CFRelease(framesetter);
CFRelease(attrString);

return frameSize.height + 10;}
于 2017-05-12T10:12:05.940 回答