UITableViewCell 布局在重用单元格之前不会更新
Posted
技术标签:
【中文标题】UITableViewCell 布局在重用单元格之前不会更新【英文标题】:UITableViewCell layout not updating until cell is reused 【发布时间】:2016-11-10 18:05:54 【问题描述】:我有一个 UITableView,我用自动调整单元格填充。
UITableView
设置相当简单:
tableView.estimatedRowHeight = 70
tableView.rowHeight = UITableViewAutomaticDimension
就像苹果在这里推荐的那样:https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithSelf-SizingTableViewCells.html
要启用自调整大小的表格视图单元格,您必须设置表格视图的 UITableViewAutomaticDimension 的 rowHeight 属性。你还必须 为estimatedRowHeight 属性赋值。只要两者 设置好这些属性后,系统使用 Auto Layout 来计算 行的实际高度。
在配置单元格时,我还会禁用/启用一些约束以实现所需的外观。这就是事情变得有趣的地方。在重新使用单元格之前,不会更新单元格布局。字面上地。您可以调用layoutIfNeeded()
、setNeedsLayout()
、layoutSubviews()
或任何其他方法,您无法强制单元格更新其布局。
所有其他方面都工作得很好:标签确实改变了它们的文本,你隐藏/取消隐藏视图,但布局被卡住,直到单元格被重用。
问题:是什么原因造成的以及如何避免这种行为?
【问题讨论】:
【参考方案1】:不幸的是,提供的答案/cmets 都没有为我解决。我总是以最初不正确的布局结束。只有在重用单元格或调用reloadData()
(在表格视图上)后,它才能正确显示。
以下是唯一对我有用的东西。我不是这种 hack 的忠实粉丝,但是在这个看似非常简单的布局问题上花了大约半天时间后,我就放弃了。 >.
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
DispatchQueue.main.async
self.tableView.reloadData()
或者,您也可以在viewDidAppear
中调用reloadData
(没有DispatchQueue
hack),但是当布局从“不正确”跳转到“正确”时,您可以清楚地看到“跳转”。
无论如何,只是想分享我的经验,希望这对其他人有所帮助。干杯!
【讨论】:
viewWillAppear 总是在主线程上调用。 这不是关于线程,而是关于异步“延迟”。 在搜索了 SO、Apple 论坛和互联网上的随机位置之后,这是唯一真正为我解决的问题。【参考方案2】:我也遇到了你的问题。而不是删除
tableView.estimatedRowHeight = 70
我刚刚在 cellForRow 方法的末尾添加了一个 layoutIfNeeded,就在返回单元格本身之前:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) as? MyCustomCell
...
cell?.layoutIfNeeded()
return cell!
结果:单元格布局总是完美的,第一次和每次重复使用。
【讨论】:
【参考方案3】:就我而言,问题是由estimatedRowHeight
引起的。
只需删除此行
tableView.estimatedRowHeight = 70
解决了我的问题。 Cell 正确更新了它的布局,它几乎解决了我的问题。
但是,您很可能会遇到另一个麻烦,因为您的单元格的高度设置为 43.5 磅。您的日志也将充满自动布局错误,其中将包括这样的一行
<NSLayoutConstraint:0x600000097570 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7fd4ee511d20.height == 43.5 (active)>
显然,如果您不提供estimatedRowHeight
,表格视图会对单元格的内容视图设置 43.5 磅的高度限制,并且如果您的单元格的“内部”高度不匹配(概率为 99.99%),然后它会将错误放入日志中。
如何避免该错误?我还不知道。 我发布了一个关于这个问题的问题,一旦我找到答案,我会在这个问题中提供一个链接。
【讨论】:
【参考方案4】:在重用单元格之前不会更新单元格布局
如果您希望 tableview 反映更改的单元格布局。
改变单元格布局后重绘表格视图
tableView.beginUpdates()
tableView.setNeedsDisplay()
tableView.endUpdates()
例如:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
guard let cell = tableView.cellForRow(at: indexPath) as? CustomCell else return
cell.collapseDescriptionLabel()
// redraw the tableView
tableView.beginUpdates()
tableView.setNeedsDisplay()
tableView.endUpdates()
【讨论】:
【参考方案5】:您不需要使用layoutIfNeeded()
、setNeedsLayout()
和layoutSubviews()
来强制布局。您可以使用tableView.beginUpdates()
和tableView.endUpdates()
。
例如:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
let cell = tableView.cellForRow(at: indexPath)
tableView.beginUpdates()
cell.heightConstraint.constant = 50
tableView.endUpdates()
【讨论】:
以上是关于UITableViewCell 布局在重用单元格之前不会更新的主要内容,如果未能解决你的问题,请参考以下文章
TouchesBegan 没有在 UIView 中作为 UITableViewCell 的子视图触发
我的 UITableViewCell 正在重用以前的单元格 UIImage
关于单元重用的自定义 UITableViewCell 约束问题