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

时间:2022-08-07 21:09:28

I have a UITableview with multiple reusable TableViewCells. In one cell I have a UITextView, that resizes itself to fit its content. Now I "just" have to resize the contentView of the TableViewCell, so I can read the while text. I already tried:

我有一个带有多个可重用的tableviewcell的UITableview。在一个单元格中,我有一个UITextView,它调整自身大小以适应其内容。现在我只需要调整TableViewCell的contentView,这样我就可以读取文本了。我已经尝试:

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

Or:

或者:

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

In the method:

的方法:

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

But it won't work.

但它不会工作。

Does anyone know how to do this?

有人知道怎么做吗?

New code:

新代码:

    @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 个解决方案

#1


7  

You need you implement heightForRowAtIndexPath.

需要实现heightForRowAtIndexPath。

Say that the data that is to be displayed in the textView is stored in a NSArray.

假设要在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

}

#2


17  

You can only resize a UITableViewCell in tableView:heightForRowAtIndexPath: delegate method.

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

You have to estimate what the size of the text will be when that method is called for every row when the tableView is loaded.

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

This is what I did to solve the problem.

这就是我解决问题的方法。

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

EDIT

编辑

While I used this solution for a while, I found a more optimal one that I would recommend using as it doesn't require allocating an entire textView in order to work, and can handle text greater than 2000.

当我使用这个解决方案的时候,我发现了一个更理想的方法,我建议使用它,因为它不需要分配整个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;
}

#3


14  

As @Rob Norback said, There is something called UITableViewAutomaticDimension.

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

For Swift, The easiest way to resize content from UITableViewCell on the fly is to just add this.

对于Swift来说,从UITableViewCell中调整内容的最简单方法就是添加这个。

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

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

#4


12  

Here's an updated version for iOS 7+ that is cleaner (no extra method)

这是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;
    }

#5


2  

This thread has been quite a while, but in iOS 8 UITableViewAutomaticDimension was introduced. You have to set constraints from the top to the bottom of the cell like a scroll view to make this work. But after that, just add the following code to viewDidLoad():

这个线程已经有很长一段时间了,但是在ios8 UITableViewAutomaticDimension中引入了。您必须从单元格的顶部到底部设置约束,就像滚动视图一样。但在此之后,只需将以下代码添加到viewDidLoad():

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 122.0

Make sure your estimated height is as close as possible to the real thing otherwise you'll get some buggy scrolling.

确保你估计的高度尽可能接近真实的东西,否则你会得到一些错误的滚动。

#6


1  

I favor this solution of Jure

我喜欢用Jure溶液

  • First, set constraints of textview to be pinned with its superview (cell's contentView in this case).
  • 首先,将textview的约束设置为与其父视图(本例中为单元格的contentView)固定。
  • Disable textView.scrollEnabled
  • 禁用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:

    实现UITextViewDelegate是这样的:

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

#7


1  

Adding these two methods to the ViewController with UITableViewAutomaticDimension should do the trick. It has worked for me when embedding a UITextView inside of a UITableViewCell with variable length text.

使用UITableViewAutomaticDimension将这两个方法添加到视图控制器中应该可以达到这个目的。在UITableViewCell中嵌入可变长度的文本时,它对我很有用。

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

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

#8


0  

In case of UILabel subview in the UITableViewCell, I accomplished auto resize of the label just by setting the label's constraints (using storyboard, Xcode 8.3.2).

在UITableViewCell中的UILabel子视图中,我通过设置标签的约束(使用storyboard, Xcode 8.3.2)实现了标签的自动调整大小。

This is working since apparently the label's and the cell's default behavior is sizeToFit. Same should work for UITextView as well.

这是有效的,因为标签和单元格的默认行为是sizeToFit。UITextView也应该是这样。

#1


7  

You need you implement heightForRowAtIndexPath.

需要实现heightForRowAtIndexPath。

Say that the data that is to be displayed in the textView is stored in a NSArray.

假设要在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

}

#2


17  

You can only resize a UITableViewCell in tableView:heightForRowAtIndexPath: delegate method.

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

You have to estimate what the size of the text will be when that method is called for every row when the tableView is loaded.

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

This is what I did to solve the problem.

这就是我解决问题的方法。

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

EDIT

编辑

While I used this solution for a while, I found a more optimal one that I would recommend using as it doesn't require allocating an entire textView in order to work, and can handle text greater than 2000.

当我使用这个解决方案的时候,我发现了一个更理想的方法,我建议使用它,因为它不需要分配整个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;
}

#3


14  

As @Rob Norback said, There is something called UITableViewAutomaticDimension.

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

For Swift, The easiest way to resize content from UITableViewCell on the fly is to just add this.

对于Swift来说,从UITableViewCell中调整内容的最简单方法就是添加这个。

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

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

#4


12  

Here's an updated version for iOS 7+ that is cleaner (no extra method)

这是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;
    }

#5


2  

This thread has been quite a while, but in iOS 8 UITableViewAutomaticDimension was introduced. You have to set constraints from the top to the bottom of the cell like a scroll view to make this work. But after that, just add the following code to viewDidLoad():

这个线程已经有很长一段时间了,但是在ios8 UITableViewAutomaticDimension中引入了。您必须从单元格的顶部到底部设置约束,就像滚动视图一样。但在此之后,只需将以下代码添加到viewDidLoad():

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 122.0

Make sure your estimated height is as close as possible to the real thing otherwise you'll get some buggy scrolling.

确保你估计的高度尽可能接近真实的东西,否则你会得到一些错误的滚动。

#6


1  

I favor this solution of Jure

我喜欢用Jure溶液

  • First, set constraints of textview to be pinned with its superview (cell's contentView in this case).
  • 首先,将textview的约束设置为与其父视图(本例中为单元格的contentView)固定。
  • Disable textView.scrollEnabled
  • 禁用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:

    实现UITextViewDelegate是这样的:

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

#7


1  

Adding these two methods to the ViewController with UITableViewAutomaticDimension should do the trick. It has worked for me when embedding a UITextView inside of a UITableViewCell with variable length text.

使用UITableViewAutomaticDimension将这两个方法添加到视图控制器中应该可以达到这个目的。在UITableViewCell中嵌入可变长度的文本时,它对我很有用。

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

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

#8


0  

In case of UILabel subview in the UITableViewCell, I accomplished auto resize of the label just by setting the label's constraints (using storyboard, Xcode 8.3.2).

在UITableViewCell中的UILabel子视图中,我通过设置标签的约束(使用storyboard, Xcode 8.3.2)实现了标签的自动调整大小。

This is working since apparently the label's and the cell's default behavior is sizeToFit. Same should work for UITextView as well.

这是有效的,因为标签和单元格的默认行为是sizeToFit。UITextView也应该是这样。