如何调整UITableViewCell的大小以适应其内容?

20

我有一个带有多个可重用 TableViewCells 的 UITableview。 其中一个单元格中有一个UITextView,该文本视图会自动调整大小以适应其内容。 现在,我“只需”调整 TableViewCell 的 contentView 的大小,以便可以阅读整个文本。我已经尝试过:

cell2.contentView.bounds.size.height = cell2.discriptionTextView.bounds.size.height; 

或者:

cell2.contentView.frame = CGRectMake(0, cell2.discriptionTextView.bounds.origin.y,     
cell2.discriptionTextView.bounds.size.width,     
cell2.discriptionTextView.bounds.size.height); 

在这个方法中:

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

但这不会起作用。

有人知道怎么做吗?

新代码:

    @implementation AppDetail

    CGFloat height;
    …

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

    cell2.TextView.text = self.text;
            [cell2.TextView sizeToFit];
            height = CGRectGetHeight(cell2.TextView.bounds);
     …
    }

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

        if (indexPath.row == 0) {
            return 143;
        }
        if (indexPath.row == 1) {
            return height;
        }

        return 0;
    }
8个回答

18

您只能在tableView:heightForRowAtIndexPath:委托方法中调整UITableViewCell的大小。

当加载tableView时,您必须估计每行调用该方法时文本的大小。

这是我解决问题的方法。

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
 {
     NSString * yourText = self.myArrayWithTextInIt[indexPath.row]; // or however you are getting the text
     return additionalSpaceNeeded + [self heightForText:yourText];
 }

 -(CGFloat)heightForText:(NSString *)text
 {
   NSInteger MAX_HEIGHT = 2000;
   UITextView * textView = [[UITextView alloc] initWithFrame: CGRectMake(0, 0, WIDTH_OF_TEXTVIEW, MAX_HEIGHT)];
   textView.text = text;
   textView.font = // your font
   [textView sizeToFit];
   return textView.frame.size.height;
  }

编辑

虽然我曾使用此解决方案一段时间,但我发现了一个更优化的解决方案,并建议使用它,因为它不需要分配整个textView以使其工作,并且可以处理超过2000个字符的文本。

-(CGFloat)heightForTextViewRectWithWidth:(CGFloat)width andText:(NSString *)text
{
    UIFont * font = [UIFont systemFontOfSize:12.0f];

    // this returns us the size of the text for a rect but assumes 0, 0 origin
    CGSize size = [text sizeWithAttributes:@{NSFontAttributeName: font}];

    // so we calculate the area
    CGFloat area = size.height * size.width;

    CGFloat buffer = whateverExtraBufferYouNeed.0f;

    // and then return the new height which is the area divided by the width
    // Basically area = h * w
    // area / width = h
    // for w we use the width of the actual text view
    return floor(area/width) + buffer;
}

你想做什么?调整textView或cell的contentView大小? - AdamG
1
我上面展示的方法将允许您根据单元格中给定textView的contentView大小重新调整单元格本身的大小。您需要做的就是找到您正在为给定单元格使用的文本。 - AdamG
你的回答不完整,additionalSpaceNeeded是什么? - user3205189
嘿,阿尔·帕西诺,这应该是不言自明的,additionalSpaceNeeded 是你在 textView 之外需要的任何额外空间。 - AdamG
你怎么改变宽度呢? - Phillip
在编辑中,我不清楚你为什么要通过将self.height乘以self.width/width来缩放它。为什么不直接返回self.height + buffer呢? - duckstar

16

正如 @Rob Norback 所说,有一个叫做 UITableViewAutomaticDimension 的东西。

对于 Swift,动态调整 UITableViewCell 内容大小的最简单方法就是添加这个。

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

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

看起来只有当单元格的所有约束都相对于该单元格设置时,才能正常工作。 - Declan McKenna

14

这是针对iOS 7+的更新版本,更加简洁(无需额外方法)。

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UIFont * font = [UIFont systemFontOfSize:15.0f];
        NSString *text = [getYourTextArray objectAtIndex:indexPath.row];
        CGFloat height = [text boundingRectWithSize:CGSizeMake(self.tableView.frame.size.width, maxHeight) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:@{NSFontAttributeName: font} context:nil].size.height;

        return height + additionalHeightBuffer;
    }

8

你需要实现 heightForRowAtIndexPath

假设要在textView中显示的数据存储在一个NSArray中。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
 CGFloat cellheight = 30; //assuming that your TextView's origin.y is 30 and TextView is the last UI element in your cell

 NSString *text = (NSString *)[textArray objectAtIndex:indexpath.row];
 UIFont *font = [UIFont systemFontOfSize:14];// The font should be the same as that of your textView
 CGSize constraintSize = CGSizeMake(maxWidth, CGFLOAT_MAX);// maxWidth = max width for the textView

 CGSize size = [text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];

 cellHeight += size.height; //you can also add a cell padding if you want some space below textView

}

好的,我现在添加了你的代码,它可以工作,但只有第二次查看UIViewController时才有效。我创建了一个CGFloat,然后将UITextView的高度分配给CGFloat。然后我在你上面发布的方法中返回创建的CGFloat。我会在上面发布我的新代码。 - David Gölzhäuser
你需要知道的第一件事是,在“cellForRowAtIndexpath”中不要设置单元格的高度,而应该在“heightForRowAtIndexpath”中设置。第二件事是,“heightForRowAtIndexpath”在“cellForRowAtIndexpath”之前被调用。这意味着在填充相同的单元格之前,你必须先计算单元格的高度。(在开始填充单元格之前,表格应该已经知道单元格的高度) - dRAGONAIR
注意:所有的 UILineBreakMode* 都已经废弃,应使用 NSLineBreakBy* 来代替。 - Raptor
你要如何改变宽度呢? - Phillip
1
你可以使UITableView变小。 - AdamG

4

我偏爱Jure的这个解决方案

  • First, set constraints of textview to be pinned with its superview (cell's contentView in this case).
  • Disable textView.scrollEnabled
  • Set

    table.rowHeight = UITableViewAutomaticDimension;
    tableView.estimatedRowHeight = 44;
    

    If finally, your code not works, then use this instead

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
        return UITableViewAutomaticDimension;
    }
    
    - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
        return 44;
    }
    
  • Implement UITextViewDelegate like this:

    - (void)textViewDidChange:(UITextView *)textView {
         CGPoint currentOffset = self.tableView.contentOffset;
         [UIView setAnimationsEnabled:NO];
         [self.tableView beginUpdates];
         [self.tableView endUpdates];
         [UIView setAnimationsEnabled:YES];
         [self.tableView setContentOffset:currentOffset animated:NO];
      }
    

还有其他没有使用故事板的例子吗? - Vyachaslav Gerchicov

3

这个主题已经有一段时间了,但在iOS 8中引入了UITableViewAutomaticDimension。你需要像滚动视图一样从上到下设置单元格的约束才能使其正常工作。但之后,只需在viewDidLoad()中添加以下代码:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 122.0

确保您的估计高度尽可能接近实际高度,否则您将会遇到一些滚动错误。


2
将这两种方法添加到具有UITableViewAutomaticDimension的ViewController中应该可以解决问题。当在变长文本的UITableViewCell内嵌入UITextView时,对我有效。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewAutomaticDimension;
}

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

1

如果UITableViewCell中有UILabel子视图,则可以通过设置标签的约束(使用storyboard,Xcode 8.3.2)来实现标签的自动调整大小。

这个方法适用的原因是标签和单元格的默认行为都是sizeToFit。同样的方法也适用于UITextView。


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