UITableViewControllerに折りたたみ可能なセクションヘッダーを実装しています。
セクションごとに表示する行数を決定する方法は次のとおりです。
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return self.sections[section].isCollapsed ? 0 : self.sections[section].items.count
}
「isCollapsed」のブール値を使用してセクション情報を保持する構造体があります。
ここに私が彼らの状態を切り替える方法があります:
private func getSectionsNeedReload(_ section: Int) -> [Int]
{
var sectionsToReload: [Int] = [section]
let toggleSelectedSection = !sections[section].isCollapsed
// Toggle collapse
self.sections[section].isCollapsed = toggleSelectedSection
if self.previouslyOpenSection != -1 && section != self.previouslyOpenSection
{
self.sections[self.previouslyOpenSection].isCollapsed = !self.sections[self.previouslyOpenSection].isCollapsed
sectionsToReload.append(self.previouslyOpenSection)
self.previouslyOpenSection = section
}
else if section == self.previouslyOpenSection
{
self.previouslyOpenSection = -1
}
else
{
self.previouslyOpenSection = section
}
return sectionsToReload
}
internal func toggleSection(_ header: CollapsibleTableViewHeader, section: Int)
{
let sectionsNeedReload = getSectionsNeedReload(section)
self.tableView.beginUpdates()
self.tableView.reloadSections(IndexSet(sectionsNeedReload), with: .automatic)
self.tableView.endUpdates()
}
すべてが正常に機能し、アニメーション化されていますが、コンソールで展開されたセクションを折りたたむと、これが表示されます[アサート]:
[アサート] preReloadFirstVisibleRow(0)の新しいグローバル行インデックスを特定できません
これは、開いているセクションが同じであるか、閉じている(折りたたまれている)か、別のセクションを開いて以前開いていたセクションを「自動閉じる」かどうかに関係なく発生します。
データについては何もしていません。それは永続的です。
誰が不足しているものを説明するのを手伝ってくれる?ありがとう
TableViewが行の再読み込み中などにそれがどこにあるかを知るために、参照として使用する「アンカー行」を見つけようとします。これはpreReloadFirstVisibleRow
と呼ばれます。すべてのセクションが折りたたまれているために、このtableViewには表示されている行がない場合があるため、tableViewはアンカーを見つけられないため混乱します。その後、上部にリセットされます。
ソリューション:折りたたまれているすべてのグループに高さ0の行を追加します。これにより、セクションが折りたたまれていても、行が存在します(高さが0pxです)。その場合、tableViewには常に参照としてフックするものがあります。これは、rowcountが0の場合にnumberOfRowsInSection
に行を追加し、indexPath.row
の前にフェイトセル値を返すことを確認することにより、それ以降のindexPath.row
呼び出しを処理することで有効になります。 datasource.visibleRows
が0の場合に必要です。
コードでデモする方が簡単です。
func numberOfSections(in tableView: UITableView) -> Int {
return datasource.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return datasource[section].visibleRows.count == 0 ? 1 : datasource[section].visibleRows.count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
datasource[section].section = section
return datasource[section]
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if datasource[indexPath.section].visibleRows.count == 0 { return 0 }
return datasource[indexPath.section].visibleRows[indexPath.row].bounds.height
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if datasource[indexPath.section].visibleRows.count == 0 { return UITableViewCell() }
// I've left this stuff here to show the real contents of a cell - note how
// the phantom cell was returned before this point.
let section = datasource[indexPath.section]
let cell = TTSContentCell(withView: section.visibleRows[indexPath.row])
cell.accessibilityLabel = "cell_\(indexPath.section)_\(indexPath.row)"
cell.accessibilityIdentifier = "cell_\(indexPath.section)_\(indexPath.row)"
cell.showsReorderControl = true
return cell
}