UITableViewCell 在首次加载时无法正确呈现
Posted
技术标签:
【中文标题】UITableViewCell 在首次加载时无法正确呈现【英文标题】:UITableViewCell not rendering properly on first load 【发布时间】:2015-05-28 16:43:57 【问题描述】:一些背景: 我正在使用 UITableView 构建一个应用程序,该应用程序显示用户可以使用 UITableViewCell 的子类对其进行投票的民意调查列表。 UITableViewCell 子类有 5 个 IBOutlet UILabel:一个问题标签,然后是 4 个选择标签。民意调查可能有 2、3 或 4 个选项,因此我可能不会显示第 3 和/或第 4 选项标签。每个标签都将“Lines”设置为 0,这样如果文本太长,它们会自动换行。
按照本教程,我设置了布局约束以确保单元格具有动态高度:http://www.raywenderlich.com/87975/dynamic-table-view-cell-height-ios-8-swift
问题标签的内容拥抱优先级为 250,而所有选择标签的优先级为 251。 问题标签的 Content Compression Resistance 优先级为 751,而所有选项标签的优先级为 752。
当我第一次加载应用程序时,第一个民意调查的问题有太多的垂直填充,第一个选择会被省略号截断。 但是,当我向下滚动然后向上滚动时,它会自行修复:问题标签包含它的内容,第一个选择显示它的所有内容。
这是我制作的显示问题的 GIF(关注顶部单元格):
这是 Interface Builder 的屏幕截图(如果有帮助的话):
这是我用来填充单元格标签的代码:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
PollTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kPollCellReuseId];
Poll *poll = [self.polls objectAtIndex: indexPath.row];
cell.questionLabel.text = poll.question;
cell.choiceLabel1.text = [(Choice *)[poll.choices objectAtIndex:0] text];
cell.choiceLabel2.text = [(Choice *)[poll.choices objectAtIndex:1] text];
BOOL hasChoice3 = poll.choices.count > 2;
cell.choiceLabel3.text = hasChoice3 ? [(Choice *)[poll.choices objectAtIndex:2] text] : @"";
cell.choiceLabel3TopConstraint.constant = hasChoice3 ? 8 : 0;
BOOL hasChoice4 = poll.choices.count > 3;
cell.choiceLabel4.text = hasChoice4 ? [(Choice *)[poll.choices objectAtIndex:3] text] : @"";
cell.choiceLabel4TopConstraint.constant = hasChoice4 ? 8 : 0;
return cell;
为什么在第一次尝试时渲染不正确?
【问题讨论】:
如果在上面代码中返回单元格之前调用[cell layoutIfNeeded]
会发生什么?
这似乎解决了它,但现在它抱怨表格中第二个单元格的自动布局:它不喜欢第三个和第四个选择标签之间的垂直间距
我降低了第 3 和第 4 个选项标签之间的垂直间距约束的优先级,现在一切似乎都很好。我是否以正确的方式解决这个问题?对于我想要完成的事情,这一切似乎有点老套。
【参考方案1】:
为我的表添加延迟 reloadData 已修复问题。
我用过,
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 500.0;
cell.layoutIfNeeded() 在返回单元格
之前
但添加延迟重新加载 tableView 为我解决了问题。该问题仅出现在 iPad 上。
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3)
self.tableView.reloadData()
另一种替代解决方案对我有用,
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3)
//Reload with delay
self.tableView.reloadData()
//Again reload with delay
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2)
self.tableView.reloadData()
【讨论】:
救了我的命,兄弟!非常感谢 致我们的 Objective-C 朋友:dispatch_after(dispatch_time(DISPATCH_TIME_NOW, .3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^ [self.tableView reloadData]; );
【参考方案2】:
我也遇到了同样的问题并使用以下技巧解决了:
extension UITableView
func reloadDataWithAutoSizingCellWorkAround()
self.reloadData()
self.setNeedsLayout()
self.layoutIfNeeded()
self.reloadData()
【讨论】:
它有效...只是拯救我的一天。但我能找出原因吗? 感谢为我工作。没有第一次重载,真的有必要吗? 这对我也有用。谢谢。我发现只有最后一次重新加载是必要的。与此解决方案无关,但问题是在初始加载时 tableview 抱怨布局问题,但此后没有,尽管它是相同的单元格。【参考方案3】:实施
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
并返回任何例如100,别忘了设置
self.tableView.rowHeight = UITableViewAutomaticDimension
viewDidLoad
【讨论】:
我不认为这是问题所在。我已经在这个 UITableView 的 ViewController 的viewDidLoad
中有这个:self.tableView.rowHeight = UITableViewAutomaticDimension; self.tableView.estimatedRowHeight = 180.0;
【参考方案4】:
根据@sikhapol 的评论:
在返回-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
中的单元格之前执行[cell layoutIfNeeded]
解决问题
【讨论】:
以上是关于UITableViewCell 在首次加载时无法正确呈现的主要内容,如果未能解决你的问题,请参考以下文章
requirejs w/ knockoutjs w/ select2 无法在首次加载时更新 observable
StreamBuilder ListView 在首次加载时从 Firestore 返回空列表