ios Iphone - 当每个单元格高度是动态的时,何时计算 tableview 的 heightForRowAtIndexPath?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4823197/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 18:41:47  来源:igfitidea点击:

Iphone - when to calculate heightForRowAtIndexPath for a tableview when each cell height is dynamic?

iosuitableviewreloaddataheightforrowatindexpath

提问by JohnRock

I have seen this question asked many times but astoundingly, I have not seen a consistent answer, so I will give it a try myself:

我已经多次看到这个问题,但令人震惊的是,我没有看到一致的答案,所以我自己试试看:

If you have a tableview containing your own custom UITableViewCells that contain UITextViews and UILabels whose height must be determined at runtime, how are you supposed to determine the height for each row in heightForRowAtIndexPath?

如果您有一个包含您自己的自定义 UITableViewCells 的 tableview,其中包含必须在运行时确定高度的 UITextViews 和 UILabels,您应该如何确定 heightForRowAtIndexPath 中每一行的高度?

The most obvious first idea is to calculate the height for each cell by calculating and then summing the heights of each view inside the cell inside of cellForRowAtIndexPath, and store that final total height for later retrieval.

最明显的第一个想法是通过计算然后求和 cellForRowAtIndexPath 中单元格内每个视图的高度来计算每个单元格的高度,并存储最终的总高度以供以后检索。

This will not work however because cellForRowAtIndexPath is called AFTER heightForRowAtIndexPath.

然而,这将不起作用,因为 cellForRowAtIndexPath 在 heightForRowAtIndexPath 之后被调用。

The only thing I can think of is to do all the calculations inside viewDidLoad, create all the UITableViewCells then, calculate the cells height and store that in a custom field inside your UITableViewCell subclass, and put each cell in an NSMutableDictionary with the indexPath as the the key, and then simply retrieve the cell from the dictionary using the indexPath inside cellForRowAtIndexPath and heightForRowAtIndexPath, returning either the custom height value or the cell object itself.

我唯一能想到的就是在 viewDidLoad 中进行所有计算,然后创建所有 UITableViewCells,计算单元格高度并将其存储在 UITableViewCell 子类中的自定义字段中,并将每个单元格放入 NSMutableDictionary 中,并将 indexPath 作为键,然后使用 cellForRowAtIndexPath 和 heightForRowAtIndexPath 中的 indexPath 从字典中简单地检索单元格,返回自定义高度值或单元格对象本身。

This approach seems wrong though because it does not make use of dequeueReusableCellWithIdentifier, instead I would be loading all the cells at once into a dictionary in my controller, and the delegate methods would be doing nothing more than retrieving the correct cell from the dictionary.

这种方法似乎是错误的,因为它没有使用 dequeueReusableCellWithIdentifier,相反,我会将所有单元格一次加载到我的控制器中的字典中,而委托方法只会从字典中检索正确的单元格。

I don't see any other way to do it though. Is this a bad idea - if so, what is the correct way to do this?

我没有看到任何其他方式来做到这一点。这是一个坏主意 - 如果是这样,那么正确的方法是什么?

回答by Obliquely

The way Apple implements UITableView is not intuitive to everyone and it's easy to misunderstand the role of heightForRowAtIndexPath:. The general intention is that this is a faster and light-on-memory method that can be called for every row in the table quite frequently. This contrasts with cellForRowAtIndexPath:which is often slower and more memory intensive, but is only called for the rows that are actually need to be displayed at any given time.

苹果实现 UITableView 的方式对每个人来说并不直观,很容易误解heightForRowAtIndexPath:. 总体意图是,这是一种更快且内存较少的方法,可以非常频繁地为表中的每一行调用。这与cellForRowAtIndexPath:通常较慢且占用更多内存但仅在任何给定时间实际需要显示的行中调用的情况形成对比。

Why do Apple implement it like this? Part of the reasonis that it's almost always cheaper (or can be cheaper if you code it right) to calculate the height of a row than it is to build and populate a whole cell. Given that in many tables the height of every cell will be identical, it is often vastly cheaper. And another part of the reasonis because iOS needs to know the size of the whole table: this allows it to create the scroll bars and set it up on a scroll view etc.

苹果为什么要这样实现?部分原因是计算行的高度几乎总是比构建和填充整个单元格更便宜(或者如果你编码正确,可能更便宜)。鉴于在许多表格中,每个单元格的高度都是相同的,因此通常要便宜得多。和的另一部分原因是因为iOS的需要知道整个表的大小:这允许它来创建滚动条,并设置它在滚动视图等。

So, unless every cell height is the same, then when a UITableView is created and whenever you send it a reloadData message, the datasource is sent one heightForRowAtIndexPath message for each cell. So if your table has 30 cells, that message gets sent 30 times. Say only six of those 30 cells are visible on screen. In that case, when created and when you send it a reloadData message, the UITableView will send one cellForRowAtIndexPath message per visible row, i.e. that message gets sent six times.

因此,除非每个单元格高度都相同,否则当创建 UITableView 并且每当您向它发送 reloadData 消息时,数据源都会为每个单元格发送一个 heightForRowAtIndexPath 消息。因此,如果您的表格有 30 个单元格,则该消息将发送 30 次。假设这 30 个单元格中只有 6 个在屏幕上可见。在这种情况下,当创建并发送 reloadData 消息时,UITableView 将在每个可见行发送一个 cellForRowAtIndexPath 消息,即该消息被发送六次。

Some people are sometimes puzzled about how to calculate a cell height without creating the views themselves. But usually this is easy to do.

有些人有时对如何在不创建视图的情况下计算单元格高度感到困惑。但通常这很容易做到。

For example, if your row heights vary in size because they hold varying amounts of text, you can use one of the sizeWithFont:methods on the relevant string to do the calculations. This is quicker than building a view and then measuring the result. Note, that if you change the height of a cell, you will need to either reload the whole table (with reloadData - this will ask the delegate for every height, but only ask for visible cells) OR selectively reload the rows where the size has changed (which, last time I checked, also calls heightForRowAtIndexPath:on ever row butalso does some scrolling work for good measure).

例如,如果您的行高大小因包含不同数量的文本而变化,您可以使用sizeWithFont:相关字符串的一种方法进行计算。这比构建视图然后测量结果更快。请注意,如果您更改单元格的高度,您将需要重新加载整个表格(使用 reloadData - 这将要求委托提供每个高度,但只要求提供可见单元格)或有选择地重新加载大小具有的行改变了(上次我检查时,它也调用heightForRowAtIndexPath:了ever row,也做了一些滚动工作以获得良好的测量)。

See this questionand perhaps also this one.

看到这个问题,也许还有这个

回答by lxt

So, I thinkyou can do this without having to create your cells all at once (which, as you suggest, is wasteful and also probably impractical for a large number of cells).

所以,我认为你可以做到这一点而不必一次创建你的细胞(正如你所建议的那样,这对于大量细胞来说是浪费的,而且可能也不切实际)。

UIKit adds a couple of methods to NSString, you may have missed them as they're not part of the main NSString documentation. The ones of interest to you begin:

UIKit 向 NSString 添加了几个方法,您可能已经错过了它们,因为它们不是主要 NSString 文档的一部分。你感兴趣的开始:

- (CGSize)sizeWithFont...

Here is the link to the Apple docs.

这是 Apple文档的链接。

In theory, these NSString additions exist for this exact problem: to figure out the size that a block of text will take up withoutneeding to load the view itself. You presumably already have access to the text for each cell as part of your table view datasource.

理论上,这些 NSString 添加是针对这个确切问题的:在不需要加载视图本身的情况下计算出文本块将占用的大小。您可能已经可以访问作为表格视图数据源的一部分的每个单元格的文本。

I say 'in theory' because if you're doing formatting in your UITextView your mileage may vary with this solution. But I'm hoping it will get you at least part way there. There's an example of this on Cocoa is My Girlfriend.

我说“理论上”是因为如果您在 UITextView 中进行格式化,您的里程可能会因此解决方案而异。但我希望它至少能让你达到目标。在Cocoa上有一个这样的例子是 My Girlfriend

回答by Kendall Helmstetter Gelner

An approach I have used in the past is to create a class variable to hold a single instance of the cell you are going to be using in the table (I call it a prototype cell). Then in the custom cell class I have a method to populate the data and determine the height the cell needs to be. Note that it can be a simpler variant of the method to really populate the data - instead of actually resizing a UILabel in a cell for example, it can just use the NSString height methods to determine how tall the UILabel would be in the final cell and then use the total cell height (plus a border on the bottom) and UILabel placement to determine the real height. YOu use the prototype cell just to get an idea of where elements are placed so you know what it means when a label is going to be 44 units high.

我过去使用的一种方法是创建一个类变量来保存您将在表格中使用的单元格的单个实例(我称之为原型单元格)。然后在自定义单元格类中,我有一个方法来填充数据并确定单元格需要的高度。请注意,它可以是真正填充数据的方法的更简单变体 - 例如,它可以仅使用 NSString 高度方法来确定 UILabel 在最终单元格中的高度,而不是实际调整单元格中 UILabel 的大小然后使用单元格总高度(加上底部的边框)和 UILabel 位置来确定实际高度。您使用原型单元格只是为了了解元素的放置位置,以便您了解标签高度为 44 个单位时的含义。

In heightForRow:I then call that method to return the height.

heightForRow:我然后调用该方法返回高度。

In cellForRow:I use the method that actually populates labels and resizes them (you never resize the UITableView cell yourself).

cellForRow:我使用实际填充标签并调整它们大小的方法(您永远不会自己调整 UITableView 单元格的大小)。

If you want to get fancy, you can also cache the height for each cell based on the data you pass in (for instance it could just be on one NSString if that's all that determines height). If you have a lot of data that's often the same it may make sense to have a permanent cache instead of just in-memory.

如果你想变得更有趣,你也可以根据你传入的数据缓存每个单元格的高度(例如,如果这决定了高度,它可以只在一个 NSString 上)。如果您有很多通常相同的数据,那么拥有永久缓存而不是仅在内存中可能更有意义。

You can also try estimating line count based on character or word count, but in my experience that never works - and when it goes wrong it usually messes up a cell and all the cells below it.

您也可以尝试根据字符或字数估算行数,但根据我的经验,这行不通——而且当它出错时,它通常会弄乱一个单元格及其下方的所有单元格。

回答by WrightsCS

This is how I calculate the height of a cell based on the amount of text in a UTextView:

这就是我根据 UTextView 中的文本量计算单元格高度的方法:

#define PADDING  21.0f

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

    if(indexPath.section == 0 && indexPath.row == 0)
    {   
        NSString *practiceText = [practiceItem objectForKey:@"Practice"];
        CGSize practiceSize = [practiceText sizeWithFont:[UIFont systemFontOfSize:14.0f] 
                   constrainedToSize:CGSizeMake(tblPractice.frame.size.width - PADDING * 3, 1000.0f)];
        return practiceSize.height + PADDING * 3;
    }

    return 72;
}

Of course, you would need to adjust the PADDINGand other variables to fit your needs, but this sets the height of the cell which has a UITextViewin it, based on the amount of text supplied. so if there are only 3 lines of text, the cell is fairly short, where as if there are 14 lines of text, the cell is rather large in height.

当然,您需要调整PADDING和 其他变量以满足您的需要,但这UITextView会根据提供的文本量设置其中包含 a 的单元格的高度。因此,如果只有 3 行文本,则单元格相当短,而如果有 14 行文本,则单元格的高度相当大。

回答by Malcolm Box

The best implementation of this that I've seen is the way the Three20 TTTableView classes do it.

我见过的最好的实现方式是 Three20 TTTableView 类的实现方式。

Basically they have a class derived from UITableViewController that delegates the heightForRowAtIndexPath:method to a class method on a TTTableCell class.

基本上,它们有一个派生自 UITableViewController 的类,该类将heightForRowAtIndexPath:方法委托给 TTTableCell 类上的类方法。

That class then returns the right height, invariably by doing the same sort of layout calculations as you do in the draw methods. By moving it to the class it avoids writing code that depends on the cell instance.

然后该类返回正确的高度,总是通过执行与绘制方法中相同的布局计算。通过将它移到类中,它避免了编写依赖于单元实例的代码。

There's really no other option - for performance reasons the framework won't create cells before asking for their heights, and you don't really want to do that either if there could be a lot of rows.

真的没有其他选择 - 出于性能原因,框架不会在询问高度之前创建单元格,如果可能有很多行,您也不想这样做。

回答by Symmetric

The problem with moving the calculation of each cell to tableView:heightForRowAtIndexPath: is that all the cells are then recalculated every time reloadData is called. Way too slow, at least for my application where there may be 100's of rows. Here's an alternative solution that uses a default row height, and caches the row heights when they are calculated. When a height changes, or is first calculated, a table reload is scheduled to inform the table view of the new heights. This does mean that rows are displayed twice when their heights change, but that's minor in comparison:

将每个单元格的计算移动到 tableView:heightForRowAtIndexPath: 的问题是每次调用 reloadData 时都会重新计算所有单元格。太慢了,至少对于我的应用程序来说可能有 100 行。下面是一个使用默认的行高度,并计算时,他们缓存行高的替代解决方案。当高度发生变化或首次计算时,将安排表重新加载以通知表视图新的高度。这确实意味着当它们的高度改变时,行会显示两次,但相比之下,这是次要的:

@interface MyTableViewController : UITableViewController {
    NSMutableDictionary *heightForRowCache;
    BOOL reloadRequested;
    NSInteger maxElementBottom;
    NSInteger minElementTop;
}

tableView:heightForRowAtIndexPath:

tableView:heightForRowAtIndexPath:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // If we've calculated the height for this cell before, get it from the height cache.  If
    // not, return a default height.  The actual size will be calculated by cellForRowAtIndexPath
    // when it is called.  Do not set too low a default or UITableViewController will request
    // too many cells (with cellForRowAtIndexPath).  Too high a value will cause reloadData to
    // be called more times than needed (as more rows become visible).  The best value is an
    // average of real cell sizes.
    NSNumber *height = [heightForRowCache objectForKey:[NSNumber numberWithInt:indexPath.row]];
    if (height != nil) {
        return height.floatValue;
    }

    return 200.0;
}

tableView:cellForRowAtIndexPath:

表视图:cellForRowAtIndexPath:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Get a reusable cell
    UITableViewCell *currentCell = [tableView dequeueReusableCellWithIdentifier:_filter.templateName];
    if (currentCell == nil) {
        currentCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:_filter.templateName];
    }

    // Configure the cell
    // +++ unlisted method sets maxElementBottom & minElementTop +++
    [self configureCellElementLayout:currentCell withIndexPath:indexPath];

    // Calculate the new cell height
    NSNumber *newHeight = [NSNumber numberWithInt:maxElementBottom - minElementTop];

    // When the height of a cell changes (or is calculated for the first time) add a
    // reloadData request to the event queue.  This will cause heightForRowAtIndexPath
    // to be called again and inform the table of the new heights (after this refresh
    // cycle is complete since it's already been called for the current one).  (Calling
    // reloadData directly can work, but causes a reload for each new height)
    NSNumber *key = [NSNumber numberWithInt:indexPath.row];
    NSNumber *oldHeight = [heightForRowCache objectForKey:key];
    if (oldHeight == nil || newHeight.intValue != oldHeight.intValue) {
        if (!reloadRequested) {
            [self.tableView performSelector:@selector(reloadData) withObject:nil afterDelay:0];
            reloadRequested = TRUE;
        }
    }

    // Save the new height in the cache
    [heightForRowCache setObject:newHeight forKey:key];

    NSLog(@"cellForRow: %@ height=%@ >> %@", indexPath, oldHeight, newHeight);

    return currentCell;
}

回答by Andrew Chung

Really good question: looking for more insight on this as well.

非常好的问题:也在寻找更多关于此的见解。

Clarifying the issue:

澄清问题:

  1. Height for Row is called Before the (cellForRowAtIndexPath)
  2. Most people calculate the height-type information within the CELL (cellForRowAtIndexPath).
  1. 在 (cellForRowAtIndexPath) 之前调用 Row 的高度
  2. 大多数人计算 CELL (cellForRowAtIndexPath) 内的高度类型信息。


Some of the solutions are surprisingly simple/effective:

一些解决方案非常简单/有效:

  • solution 1: force the heightForRowAtIndexPath to calculate the the cell's specs. Massimo Cafaro Sept 9th

  • solution 2: do a first pass "standard size" for the cells, cache results when you do have cell heights, then reload the table using the new heights - Symmetric

  • solution 3: the other interesting answer seems to be the involving three20 but based on the answer it seems that there isn't a cell drawn in storyboard/xib which would make this "problem" much easier to solve.

  • 解决方案 1:强制 heightForRowAtIndexPath 计算单元格的规格。马西莫·卡法罗 9 月 9 日

  • 解决方案 2:对单元格执行第一遍“标准大小”,当您有单元格高度时缓存结果,然后使用新高度重新加载表格 - 对称

  • 解决方案 3:另一个有趣的答案似乎是涉及three20,但根据答案似乎没有在故事板/xib 中绘制的单元格会使这个“问题”更容易解决。

回答by xeravim

as i searched over and over about this topic, finally this logic came to my thought. a simple code, but maybe not efficient enough, but so far it's the best i can find.

当我一遍又一遍地搜索这个话题时,我终于想到了这个逻辑。一个简单的代码,但可能不够高效,但到目前为止它是我能找到的最好的。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  NSDictionary * Object=[[NSDictionary alloc]init];
  Object=[Rentals objectAtIndex:indexPath.row];
  static NSString *CellIdentifier = @"RentalCell";
  RentalCell *cell = (RentalCell *)[tableView
                                  dequeueReusableCellWithIdentifier:CellIdentifier];
  if (cell == nil)
  {
      cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
  }
   NSString* temp=[Object objectForKey:@"desc"];
   int lines= (temp.length/51)+1;
   //so maybe here, i count how many characters that fit in one line in this case 51
   CGRect correctSize=CGRectMake(cell.infoLabel.frame.origin.x, cell.infoLabel.frame.origin.y,    cell.infoLabel.frame.size.width, (15*lines));
   //15 (for new line height)
   [cell.infoLabel setFrame:correctSize];
   //manage your cell here
}

and here is the rest of the code

这是其余的代码

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

    NSDictionary * Object=[[NSDictionary alloc]init];
    Object=[Rentals objectAtIndex:indexPath.row];
    static NSString *CellIdentifier = @"RentalCell";
    RentalCell *cells = (RentalCell *)[tableView
                                  dequeueReusableCellWithIdentifier:CellIdentifier];
    NSString* temp=[Object objectForKey:@"desc"];
    int lines= temp.length/51;

    return (CGFloat) cells.bounds.size.height + (13*lines);
}

回答by JohnRock

I went with the idea I originally proposed, which appears to work fine, whereby I load all the custom cells ahead of time in viewDidLoad, store them in a NSMutableDictionary with their index as the key. I am posting the relevant code and would love any critiques or opinions anyone has about this approach. Specifically, I am not sure whether there is any memory leak issue with the way I am creating the UITableViewCells from the nib in viewDidLoad - since I don't release them.

我采用了我最初提出的想法,它似乎工作正常,我提前在 viewDidLoad 中加载所有自定义单元格,将它们存储在 NSMutableDictionary 中,并以它们的索引为键。我正在发布相关代码,并希望有人对这种方法提出任何批评或意见。具体来说,我不确定我从 viewDidLoad 中的笔尖创建 UITableViewCells 的方式是否存在任何内存泄漏问题 - 因为我没有释放它们。

@interface RecentController : UIViewController <UITableViewDelegate, UITableViewDataSource> {

NSArray *listData;
NSMutableDictionary *cellBank;

}

@property (nonatomic, retain) NSArray *listData;
@property (nonatomic, retain) NSMutableDictionary *cellBank;
@end



@implementation RecentController

@synthesize listData;
@synthesize cellBank;

---

- (void)viewDidLoad {

---

self.cellBank = [[NSMutableDictionary alloc] init];

---

//create question objects…

--- 

NSArray *array = [[NSArray alloc] initWithObjects:question1,question2,question3, nil];

self.listData = array;

//Pre load all table row cells
int count = 0;
for (id question in self.listData) {

    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"QuestionHeaderCell" 
                                                 owner:self 
                                               options:nil];
    QuestionHeaderCell *cell;

    for (id oneObject in nib) {
        if([oneObject isKindOfClass:[QuestionHeaderCell class]])
            cell = (QuestionHeaderCell *) oneObject;

            NSNumber *key = [NSNumber numberWithInt:count];
            [cellBank setObject:[QuestionHeaderCell makeCell:cell 
                                                  fromObject:question] 
                         forKey:key];
            count++;

    }
}

[array release];
[super viewDidLoad];
}



#pragma mark -
#pragma mark Table View Data Source Methods

-(NSInteger) tableView: (UITableView *) tableView
numberOfRowsInSection: (NSInteger) section{

return [self.listData count];

}

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

NSNumber *key = [NSNumber numberWithInt:indexPath.row];
return [cellBank objectForKey:key];


}

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

NSNumber *key = [NSNumber numberWithInt:indexPath.row];
return [[cellBank objectForKey:key] totalCellHeight];

}

@end



@interface QuestionHeaderCell : UITableViewCell {

UITextView *title;
UILabel *createdBy;
UILabel *category;
UILabel *questionText;
UILabel *givenBy;
UILabel *date;
int totalCellHeight;

}

@property (nonatomic, retain) IBOutlet UITextView *title;
@property (nonatomic, retain) IBOutlet UILabel *category;
@property (nonatomic, retain) IBOutlet UILabel *questionText;
@property (nonatomic, retain) IBOutlet UILabel *createdBy;
@property (nonatomic, retain) IBOutlet UILabel *givenBy;
@property (nonatomic, retain) IBOutlet UILabel *date;
@property int totalCellHeight;

+(UITableViewCell *) makeCell:(QuestionHeaderCell *) cell 
               fromObject:(Question *) question;

@end



@implementation QuestionHeaderCell
@synthesize title;
@synthesize createdBy;
@synthesize givenBy;
@synthesize questionText;
@synthesize date;
@synthesize category;
@synthesize totalCellHeight;







- (void)dealloc {
[title release];
[createdBy release];
[givenBy release];
[category release];
[date release];
[questionText release];
[super dealloc];
}

+(UITableViewCell *) makeCell:(QuestionHeaderCell *) cell 
                 fromObject:(Question *) question{


NSUInteger currentYpos = 0;

cell.title.text = question.title;

CGRect frame = cell.title.frame;
frame.size.height = cell.title.contentSize.height;
cell.title.frame = frame;
currentYpos += cell.title.frame.size.height + 2;


NSMutableString *tempString = [[NSMutableString alloc] initWithString:question.categoryName];
[tempString appendString:@"/"];
[tempString appendString:question.subCategoryName];

cell.category.text = tempString;
frame = cell.category.frame;
frame.origin.y = currentYpos;
cell.category.frame = frame;
currentYpos += cell.category.frame.size.height;

[tempString setString:@"Asked by "];
[tempString appendString:question.username];
cell.createdBy.text = tempString;

frame = cell.createdBy.frame;
frame.origin.y = currentYpos;
cell.createdBy.frame = frame;
currentYpos += cell.createdBy.frame.size.height;


cell.questionText.text = question.text;
frame = cell.questionText.frame;
frame.origin.y = currentYpos;
cell.questionText.frame = frame;
currentYpos += cell.questionText.frame.size.height;


[tempString setString:@"Advice by "];
[tempString appendString:question.lastNexusUsername];
cell.givenBy.text = tempString;
frame = cell.givenBy.frame;
frame.origin.y = currentYpos;
cell.givenBy.frame = frame;
currentYpos += cell.givenBy.frame.size.height;


cell.date.text = [[[MortalDataStore sharedInstance] dateFormat] stringFromDate: question.lastOnDeck];
frame = cell.date.frame;
frame.origin.y = currentYpos-6;
cell.date.frame = frame;
currentYpos += cell.date.frame.size.height;

//Set the total height of cell to be used in heightForRowAtIndexPath
cell.totalCellHeight = currentYpos;

[tempString release];
return cell;

}

@end

回答by Massimo Cafaro

Here is what I do in very simple case, a cell containing a note held in a label. The note itself is constrained to a maximum length I am imposing, so I use a multi-line UILabel and I compute dynamically the correct eight for each cell as shown in the following example. You can deal with an UITextView pretty much the same.

这是我在非常简单的情况下所做的,一个包含在标签中的笔记的单元格。注释本身被限制为我施加的最大长度,因此我使用多行 UILabel 并动态计算每个单元格的正确 8,如下面的示例所示。您可以几乎相同地处理 UITextView。

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

    // Configure the cell...
    Note *note = (Note *) [fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = note.text;
    cell.textLabel.numberOfLines = 0; // no limits

    DateTimeHelper *dateTimeHelper = [DateTimeHelper sharedDateTimeHelper];
    cell.detailTextLabel.text = [dateTimeHelper mediumStringForDate:note.date];

    cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;


    return cell;
}


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

    //NSLog(@"heightForRowAtIndexPath: Section %d Row %d", indexPath.section, indexPath.row);
    UITableViewCell *cell = [self tableView: self.tableView cellForRowAtIndexPath: indexPath];
    NSString *note = cell.textLabel.text;
    UIFont *font = [UIFont fontWithName:@"Helvetica" size:14.0];
    CGSize constraintSize = CGSizeMake(280.0f, MAXFLOAT);
    CGSize bounds = [note sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
    return (CGFloat) cell.bounds.size.height + bounds.height;

}