概括
鉴于我们并不总是知道单元格的框架或其内容视图将是什么(由于编辑、旋转、辅助视图等),tableView:heightForRowAtIndexPath:
当单元格包含可变高度文本字段或标签?
我的其中一个UITableViewController's
包含以下演示文稿:带有 UITextView 的 UITableViewCell。
UITextView 应该和 UITableViewCell 一样宽高。
我创建了 UITableViewCell 子类,然后用 UITextView 初始化它(UITextView 是我的 UITableViewController 的私有字段)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = @"TextViewCell";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[BTExpandableTextViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier textView:_notesTextView] autorelease];
}
return cell;
}
我在 UITableViewCell 子类中实现了以下方法:
- (void)layoutSubviews{
[super layoutSubviews];
CGFloat height = [textView.text sizeWithFont:textView.font constrainedToSize:CGSizeMake(textView.frame.size.width, MAXFLOAT)].height + textView.font.lineHeight;
textView.frame = CGRectMake(0, 0, self.contentView.frame.size.width, (height < textView.font.lineHeight * 4) ? textView.font.lineHeight * 4 : height);
[self.contentView addSubview:textView];
}
当然我实现了以下 UITableViewDataSource 方法(看!我正在使用 self.view.frame.size.width (但我真的需要 UITableViewCell contentView 框架宽度):
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath{
CGFloat height = [_notesTextView.text sizeWithFont:_notesTextView.font
constrainedToSize:CGSizeMake(self.view.frame.size.width, MAXFLOAT)].height;
CGFloat groupedCellCap = 20.0;
height += groupedCellCap;
if(height < [BTExpandableTextViewCell minimumTextViewHeightWithFont:_notesTextView.font]){
height = [BTExpandableTextViewCell minimumTextViewHeightWithFont:_notesTextView.font];
}
return height;
}
我也实现了以下方法(这不是那么重要,但无论如何我都会发布它,只是为了解释单元格的高度是动态的,它会在 UITextView 中更改文本后缩小或扩大)
- (void)textViewDidChange:(UITextView *)textView{
CGFloat height = [_notesTextView.text sizeWithFont:_notesTextView.font
constrainedToSize:CGSizeMake(_notesTextView.frame.size.width, MAXFLOAT)].height;
if(height > _notesTextView.frame.size.height){
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
}
现在,我的问题是: 加载视图后, UITableViewController 按以下顺序调用方法:(为了简化,我删除了一些,如 titleForHeaderInSection 等)
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath{
只有这样
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
看!我应该在 cellForRowAtIndexPath 之前返回正确的 UITableViewCell 高度!这意味着:我不知道 UITableViewCell contentView 框架。而且我无法以编程方式获得它。
此宽度可以是以下之一:
- iPhone 普通桌子,纵向
- iPhone 普通桌子,横向
- iPhone 分组表,纵向
- iPhone 分组表,横向
- 和 iPad 相同(另外 4 个值)
并且不要忘记,因为 UITableViewCell 附件类型,或者因为 UITableView 编辑状态,contentView 框架可以更小。(例如,如果我们有 UITableViewCell 与任何高度的多行 UILabel 在任何编辑状态和任何附件视图)
所以这个问题是根本的:我只是无法获得单元格 contentView 框架宽度进行约束,因为我应该在单元格布局 contentView 之前返回这个高度。(顺便说一句,这很合乎逻辑)但是这个 contentView 框架真的很重要。
当然有时我可以准确地知道这个宽度并“硬编码”它(例如:UITableViewCellAccessoryDisclosureIndicator 有 20 px 宽度,而 tableView 不能处于编辑状态,那么我可以写 self.view.frame.size.width - 20 和任务已经完成了)!或者有时 contentView 等于 UITableViewController 的视图框架!
有时我在 -tableView:heightForRowAtIndexPath: 方法中使用 self.view.frame.width 。(就像现在一样,它工作得很好,但由于分组的 UITableView 并不完美,应该减去一些常量值,它们是不同的2 个设备 * 2 个方向)
有时我在 UITableViewCell 中有一些#defined 常量(如果我确切地知道宽度)......
有时我正在使用一些虚拟的预分配 UITableViewCell (这很愚蠢,但有时非常优雅且易于使用)......
但我不喜欢那种东西。
最好的决定是什么? 也许我应该创建一些辅助类,它将使用以下参数进行初始化:附件视图、设备方向、设备类型、表视图编辑状态、表视图样式(普通、分组)、控制器视图框架和其他一些,这将包括一些常量(如分组的 tableView 偏移量等)并使用它来查找预期的 UITableViewCell contentView 宽度?;)
谢谢