我的应用程序需要具有可变高度表格单元格(因为每个表格单元格的高度不同,而不是每个单元格都需要能够自行调整大小)。
我有一个目前有效的解决方案,但它很麻烦而且很慢。
我目前的解决方案:
在表格单元格渲染之前,我通过在其数据上调用-sizeWithFont:constrainedToSize:
等大小调整方法来计算每个单元格需要多高。然后我将高度加起来,允许一些填充并将结果存储在数据中。
然后,当我的UITableViewDelegate收到-tableview:heightForRowAtIndexPath:
时,我会计算出为该单元格呈现的项目并返回我之前计算的高度。
正如我所说的,这是有效的,但是当您按顺序执行数百个项目时调用-sizeWithFont:constrainedToSize:
非常慢,我觉得可以做得更好。
因此,为了实现这一点,我必须维护两部分代码 - 一部分用于计算单元格高度,另一部分用于在时间到来时实际绘制单元格。
如果关于模型项的任何更改,我不得不更新这两个代码块,现在又一次它们仍然不能完美匹配,有时会导致表格单元格对于给定项目而言略微过小或者太大了。
我建议的解决方案:
所以我想取消预先计算细胞高度。 A)因为它打破了MVC范式而B)因为它很慢。
因此,我的细胞自我吸收,因此,最终得到正确的细胞高度。我的问题是我无法告诉表格在绘制之前查看单元格的高度 - 到时候为时已晚。
我尝试在-cellForRowAtIndexPath:
内调用-tableView:heightForRowAtIndexPath:
,但这会陷入无限循环,因为第一个在某个时刻调用第二个,反之亦然(至少这是我在看到的时候)尝试过。)
所以这个选项是不可能的。
如果我没有在行委托方法的高度中指定大小,那么表视图就会变得棘手。细胞是完美的高度,但它们的x位置是固定高度的细胞。
Messed Table Cells http://jamsoftonline.com/images/messed_table_cells.png
注意底部单元格的大小是正确的 - 它只是与前一个单元格重叠,而前一个单元格与之前的单元格重叠,依此类推。
同样使用这种方法,在滚动时会出现一些伪像,我认为这些伪像可能与单元格的重用标识符有关。
因此,非常感谢任何帮助。
答案 0 :(得分:38)
这是我使用的。 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)];
}
答案 1 :(得分:2)
只是一个想法:
如果您有六种不同类型的单元格,每种单元格都有自己的标识符和固定高度,那该怎么办?一个用于单线电池,另一个用于双线电池等......
每次模型更改时,计算该行的高度,然后找到最接近您所需高度的最近单元格类型。使用模型保存该celltype标识符。你还可以在模型中存储该单元格的固定行高,这样你就可以在tableview中返回它:heightForRowAtIndexPath调用(我不会太忙于强制它在单元类内部计算 - 技术上它不是单元格绘制功能以及tableview用于决定创建哪种单元格类型的更多内容。
在运行时,当要求返回该行的单元格时,您需要做的就是创建(或从单元缓存中获取)具有单元格类型标识符的单元格,加载值并且您很高兴去
如果单元格高度计算太慢,那么您可以使用tableview缓存执行的相同技巧,并且仅在单元格进入视图时按需执行。在任何给定的时间,您只需要为视图中的单元格执行此操作,然后仅在单个单元格中滚动到两端的视图中。
答案 2 :(得分:0)
我知道由于你提到的无限循环,这对你不起作用,但我在调用单元格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)];
}