无法扩展 UITableView
Posted
技术标签:
【中文标题】无法扩展 UITableView【英文标题】:Trouble Expanding UITableView 【发布时间】:2020-01-16 00:21:46 【问题描述】:目标和背景
我正在尝试使用this tutorial 创建一个可扩展的 UITableView。但是,我希望表格更新其容器的高度,以便新高度与内容匹配。问题是这会在表格的最后一个标题(部分)上产生视觉故障 - 但仅在第一次执行动画时。
这就是它的样子:link
我的想法是,随着表格展开隐藏的单元格,最后一行被推到视野之外。所以当我更新视图的高度时,它必须重新绘制最后一个单元格(注意重新加载时的颜色变化)。不过,我不确定奇怪的滑入式动画来自哪里。
问题
我将如何消除此故障或更好地完成此任务?
代码
这是我的层次结构:
+-- ParentVC
| +-- ParentView
| | +-- CustomTableVC's View
| | | +-- Custom UITable
(CustomTableVC is a child of ParentVC)
这就是我重新加载点击部分并设置新高度的方式
// === CustomTableVC === //
func toggleSection(_ header: PTTableHeader, section: Int)
...
// Reload the section with a drop-down animation
table.reloadSections(NSIndexSet(index: section) as IndexSet, with: .automatic)
// Update the height of the container view
preferredContentSize.height = table.contentSize.height
// Height for section headers and rows: 44 (including estimated)
这是父级的更新方式:
// === ParentVC === //
override func preferredContentSizeDidChange(forChildContentContainer container: UIContentContainer)
super.preferredContentSizeDidChange(forChildContentContainer: container)
if let child = container as? PTTable
customTableVC.view.layoutIfNeeded()
customTableViewHeightAnchor.constant = child.preferredContentSize.height
UIView.animate(withDuration: 3, animations:
view.layoutIfNeeded()
)
// Height anchor starts at parentView's height / 3 because
// I'm not sure how to make it match the table's contentSize from the get-go
删除view.layoutIfNeeded()
会导致最后一部分不执行滑入动画,但仍会执行glitch out。
在 iPhone 11 Pro(模拟器)上运行。
【问题讨论】:
"我希望表格更新其容器的高度,以便新的高度与内容相匹配。"只是想知道为什么您尝试让表格与内容高度匹配。它不会自己处理吗? @Kanongata 该表知道其新的所需高度,但由于 CustomTableVC 的视图小于该高度,它没有增长空间。所以它最终会启用滚动。 很公平。查看您的 2 个 gif,在展开单元格之前和折叠单元格之后,内容高度似乎不一致。折叠单元格后,内容高度大于初始状态。如果从那时起您对这种行为感到满意 - 可以尝试最初设置内容高度以匹配单元格展开然后折叠后的高度。 @Kanongata 我对其进行了测试,这似乎解决了单元格重新加载问题,但这意味着如果我有足够的隐藏单元格,我将需要将初始高度设置得非常大:/ 我能想到的最佳选择是为展开和折叠的单元格设置 2 个不同的重用标识符。因此,只要一个单元格被折叠,就不需要绘制所有这些 UIView。如果它被扩展,你可以用 tableView 更新来动画化这个变化。 【参考方案1】:反射
我让它工作了。一旦我弄清楚了,这个技巧实际上非常简单。我仍然认为这有点令人费解/有异味,但它适用于我的目的以及我以前使用的method。
解决方案
基本上,我设置了preferredContentSize 之前我重新加载这些部分。这会提醒 ParentVC 在实际发生任何变化之前开始制作动画。这意味着表格现在有空间将底部移动到其中而无需重新加载它。
代码
// === CustomTableVC === //
func toggleSection(_ header: PTTableHeader, section: Int)
...
// Predict the height of the table BEFORE reloading it
predictHeight(section: section, willExpand: isExpanding) // Change isExpanding with whatever Bool is tracking the expand/collapse state of the section
// THEN reload the section with a drop-down animation
table.reloadSections(NSIndexSet(index: section) as IndexSet, with: .automatic)
// Optionally do the above with an animation using UIView.animate() or UIView.transition()
// And FINALLY update the height of the container view
// This one is probably optional, but it will be more exact depending on what methods you use to predict the height in predictHeight()
preferredContentSize.height = table.contentSize.height
func predictHeight(section: Int, willExpand: Bool)
// Get the heights of all the known headers/footers/rows
let tableSectionsHeight = CGFloat(table.numberOfSections) * (table.estimatedSectionHeaderHeight + table.sectionFooterHeight)
let tableCellsHeight = CGFloat(table.visibleCells.count) * table.estimatedRowHeight
// Calculate the height of the section being expanded/collapsed
// With the method I used, I can't just do table.numberOfRows(inSection: Int) since expanding/collapsing is essentially just adding/removing those rows
// Instead I need to store a reference to the number of rows per section and access it via that array, object, etc.
let sectionContentHeight = willExpand ? CGFloat(rowCounts[section]) * table.estimatedRowHeight : 0 // 0 if collapsing
// Set the preferredContentSize so that the ParentVC picks it up
preferredContentSize.height = tableSectionsHeight + tableCellsHeight + sectionContentHeight
【讨论】:
以上是关于无法扩展 UITableView的主要内容,如果未能解决你的问题,请参考以下文章