最近我遇到了由heightForRowAtIndexPath:
引起的效率问题。每次你必须绘制单元格你的书呆子来创建它并计算它的大小 - 它太长了!
有人会说,为什么不使用estimatedHeightForRowAtIndexPath:
,但是当你在这里通过估算时,你只是松散的准确性,所以当你滚动到顶部时,一些细胞根本看不到...
我想扩大我对此事的了解。来自Twitter,Facebook或Instagram的人是如何做到的?
答案 0 :(得分:1)
我想你的意思是指细胞高度由细胞内容决定的情况。
通常,在布局过程中计算该情况下的单元格的高度。没有其他方法可以计算该高度而不至少执行一次布局。
例如,您有一个带描述标签的单元格。您需要将整个描述显示为多行文本而不截断它。因此,您必须制作可变高度的描述标签。
当tableview询问您单元格的高度时,您必须计算描述文本所需的行数。这与您在单元格内容布局期间执行的工作完全相同。
在一般情况下,布局过程是一些轻量级计算。我们的想法是从单元类中提取该计算代码,并根据需要直接访问它们。
在下面的例子中:
CellLayoutParams
包含计算布局时应考虑的初始信息。这里是应该由单元格和单元格宽度显示的数据。
@interface CellLayoutParams : NSObject {
@property (nonatomic, copy) NSString* title;
@property (nonatomic, copy) NSString* description;
@property (nonatomic, assign) CGFloat width;
- (BOOL)isEqualToLayoutParams:(CellLayoutParams*)params;
@end
CellStyle
是一个描述单元格样式属性的对象。例如。描述标签的字体,各种单元格填充,边距和插图。
@interface CellStyle : NSObject
@property(nonatomic, strong) UIFont* titleFont;
@property(nonatomic, strong) UIFont* descriptionFont;
- (struct CellLayoutInfo)layoutInfoForParams:(CellLayoutParams*)params;
@end
@implementation CellStyle
- (struct CellLayoutInfo)layoutInfoForParams:(CellLayoutParams*)params {
CellLayoutInfo layoutInfo;
const CGPoint contentOffset = CGPointMake(kLeftMargin, kTopMargin);
const CGFloat contentWidth = params.width - kAccessoryWidth - kLeftMargin;
NSString* descriptionValue = params.description;
CGSize descriptionSize = [descriptionValue sizeWithFont: [self descriptionFont]
constrainedToSize: CGSizeMake(contentWidth, CGFLOAT_MAX)];
layoutInfo.descriptionFrame.size = descriptionSize;
layoutInfo.descriptionFrame.origin = CGPointMake(contentOffset.x, layoutInfo.titleFrame.origin.y + layoutInfo.titleFrame.size.height + kVerticalInset);
layoutInfo.preferredHeight = layoutInfo.descriptionFrame.origin.y + descriptionSize.height + kBottomMargin;
return layoutInfo
}
@end
CellLayoutInfo
是一个具有计算出的布局信息的结构:计算出的帧和首选高度值。
typedef struct CellLayoutInfo {
CGRect titleFrame;
CGRect descriptionFrame;
CGFloat preferredHeight;
} CellLayoutInfo;
您只需执行布局计算即可获得首选高度:
- (CGFloat)tableView:(UITableView *)table heightForRowAtIndexPath:(NSIndexPath*)indexPath {
MyData* dataItem = [self.data objectAtIndex:indexPath.row];
CellLayoutParams* layoutParams = [CellLayoutParams new];
layoutParams.description = dataItem.description;
layoutParams.width = table.bounds.size.width;
CellStyle* cellStyle = [CellStyle new];
CellLayoutInfo layoutInfo = [cellStyle layoutInfoForParams:layoutParams];
return layoutInfo.preferredHeight;
}
在单元格的layoutSubviews
中,您可以访问相同的计算布局值:
- (void) layoutSubviews {
[super layoutSubviews];
CellLayoutParams* layoutParams = [CellLayoutParams new];
layoutParams.description = self.descriptionLabel.text;
layoutParams.width = self.bounds.size.width;
CellStyle* cellStyle = [CellStyle new];
CellLayoutInfo layoutInfo = [cellStyle layoutInfoForParams:layoutParams];
self.titleLabel.frame = layoutInfo.titleFrame;
self.descriptionLabel.frame = layoutInfo.descriptionFrame;
}
很少有事情需要注意:
唯一的缺点是您必须在代码中定义所有样式和布局。