如何在 iPhone 上正确设置可变高度表格单元格?
Posted
技术标签:
【中文标题】如何在 iPhone 上正确设置可变高度表格单元格?【英文标题】:How can I do variable height table cells on the iPhone properly? 【发布时间】:2009-09-18 08:57:53 【问题描述】:我的应用需要具有可变高度的表格单元格(因为每个表格单元格的高度不同,而不是每个单元格都需要能够自行调整大小)。
我有一个目前有效的解决方案,但它很笨拙且缓慢。
我目前的解决方案:
在呈现表格单元格之前,我通过调用诸如-sizeWithFont:constrainedToSize:
之类的大小调整方法来计算每个单元格需要多高的数据。然后我将高度相加,允许一些填充并将结果与数据一起存储。
然后,当我的 UITableViewDelegate 收到 -tableview:heightForRowAtIndexPath:
时,我会计算出将为该单元格呈现哪个项目并返回我之前计算的高度。
正如我所说,这行得通,但是当您按顺序为数百个项目执行此操作时,调用-sizeWithFont:constrainedToSize:
非常慢,我觉得可以做得更好。
因此,要使其正常工作,我必须维护两部分代码 - 一部分用于计算单元格高度,另一部分用于在时机成熟时实际绘制单元格。
如果模型项发生任何变化,我必须更新这两个代码块,但有时它们仍然不能完美匹配,有时会导致表格单元格对于给定项来说稍微太小,或太大。
我提出的解决方案:
所以我想取消预先计算单元格高度。 A)因为它打破了 MVC 范式,B)因为它很慢。
所以我的单元格会自行绘制,结果,单元格高度正确。我的问题是我无法在绘制之前告诉表格视图单元格的高度 - 到那时为时已晚。
我尝试从-tableView:heightForRowAtIndexPath:
中调用-cellForRowAtIndexPath:
,但这陷入了无限循环,因为第一个在某个时候调用了第二个,反之亦然(至少这是我在尝试时看到的)。
所以这个选项是不可能的。
如果我没有为行委托方法指定高度的大小,那么表格视图就会变得混乱。单元格的高度是完美的,但它们的 x 位置是固定高度的单元格的位置。
Messed Table Cells http://jamsoftonline.com/images/messed_table_cells.png
注意底部单元格的大小如何正确 - 它只是与前一个单元格重叠,前一个单元格与其前一个单元格重叠,依此类推。
同样使用这种方法,在滚动时会出现一些伪影,我认为这可能与单元格的重用标识符有关。
因此,我们将不胜感激。
【问题讨论】:
我也有同样的问题。 -cellForRowAtIndexPath: 调用 -tableView:heightForRowAtIndexPath: 如果在后者中调用(请注意,如果在后者中没有调用,它不会调用后者)让我发疯。 【参考方案1】:这是我使用的。 NSString 有一个方法可以根据字体信息和你给它的高度/宽度限制告诉你文本框的尺寸。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
NSString *text = [self getTextForIndexPath:indexPath];
UIFont *font = [UIFont systemFontOfSize:14];
CGSize size = [self getSizeOfText:text withFont:font];
return (size.height + 11); // I put some padding on it.
然后你写一个方法拉这个单元格的文本...
- (NSString *)getTextForIndexPath:(NSIndexPath *)indexPath
NSString *sectionHeader = [self.tableSections objectAtIndex:[indexPath section]];
NSString *sectionContent = [self.tableData objectForKey:sectionHeader];
return sectionContent;
这是获取文本的大小。
- (CGSize)getSizeOfText:(NSString *)text withFont:(UIFont *)font
return [text sizeWithFont:font constrainedToSize:CGSizeMake(280, 500)];
【讨论】:
如何在分组表视图中仅对一个单元格使用此方法?我想根据单元格内 textView 的高度返回单元格的高度... 嗨。我想知道self.tableSections
和self.tableData
是什么。我知道它们是 NSArray 和 NSDictionary,但这是否意味着您为这些部分的内容制作了一个表格部分的数组和一个字典?我问是因为我只使用了一个部分,而且我似乎无法让它工作。【参考方案2】:
只是一个想法:
如果你有六种不同类型的单元格,每个单元格都有自己的标识符和固定的高度。一个用于单行单元格,另一个用于两行单元格,等等......
每次您的模型发生变化时,计算该行的高度,然后找到最接近您需要的高度的单元格类型。将该单元类型标识符与模型一起保存。您还可以在模型中存储该单元格的固定行高,以便您可以在 tableview:heightForRowAtIndexPath 调用中返回它(我不会太担心强制它在单元格类本身内部进行计算——从技术上讲,它不是一部分单元格绘制功能以及更多表格视图用来决定创建哪种单元格类型的功能)。
1234563 .如果单元格高度计算太慢,那么您可以采用与 tableview 缓存相同的技巧,仅在单元格进入视图时按需执行。在任何给定时间,您只需要对视图中的单元格执行此操作,然后只需对单个单元格执行此操作,因为它在任一端滚动到视图中。
【讨论】:
我过去曾玩弄过这个想法,但无法让它完全按照我的意愿行事。但也许我可以再试一次。【参考方案3】:由于您提到的无限循环,我意识到这对您不起作用,但是我在调用单元格 layoutSubViews 方法方面取得了一些成功
虽然由于对 cellForRowAtIndexPath 和 layoutSubViews 的多次调用,这可能会有点低效,但我发现代码更简洁。
-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
MyCell *cell = (MyCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];
[cell layoutSubviews];
return CGRectGetHeight(cell.frame);
并且在布局代码中:
- (void)layoutSubviews
[super layoutSubviews];
//First expand the label to a large height to so sizeToFit isn't constrained
[self.myArbitrarilyLengthLabel setFrame:CGRectMake(self.myArbitrarilyLengthLabel.frame.origin.x,
self.myArbitrarilyLengthLabel.frame.origin.y,
self.myArbitrarilyLengthLabel.frame.size.width,
1000)];
//let sizeToFit do its magic
[self.myArbitrarilyLengthLabel sizeToFit];
//resize the cell to encompass the newly expanded label
[self setFrame:CGRectMake(self.frame.origin.x,
self.frame.origin.y,
self.frame.size.width,
CGRectGetMaxY(self.myArbitrarilyLengthLabel.frame) + 10)];
【讨论】:
以上是关于如何在 iPhone 上正确设置可变高度表格单元格?的主要内容,如果未能解决你的问题,请参考以下文章