可折叠部分:[Assert] 无法确定 preReloadFirstVisibleRow (0) 的新全局行索引

iOS*_*Fun 11 assert collapsable ios swift uitableviewsectionheader

我正在 UITableViewController 中实现可折叠的部分标题。

以下是我确定每个部分显示多少行的方法:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
    return self.sections[section].isCollapsed ? 0 : self.sections[section].items.count
}
Run Code Online (Sandbox Code Playgroud)

有一个结构体保存了带有“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()
}
Run Code Online (Sandbox Code Playgroud)

一切正常,动画效果很好,但是在控制台中折叠展开的部分时,我得到了这个 [Assert]:

[断言] 无法确定 preReloadFirstVisibleRow (0) 的新全局行索引

发生这种情况,无论它是相同的打开部分、关闭(折叠),还是我打开另一个部分并“自动关闭”先前打开的部分。

我没有对数据做任何事情;那是坚持。

任何人都可以帮助解释缺少什么吗?谢谢

Byr*_*see 14

为了让 tableView 在重新加载行等时知道它在哪里,它会尝试找到一个用作参考的“锚行”。这称为preReloadFirstVisibleRow. 由于所有部分都被折叠,此 tableView 在某些时候可能没有任何可见的行,因此 tableView 会因为找不到锚点而感到困惑。然后它会重置到顶部。

解决方案: 为每个折叠的组添加一个 0 高度的行。这样,即使部分折叠,仍然存在一行(尽管高度为 0px)。然后 tableView 总是有一些东西可以作为参考。numberOfRowsInSection如果 rowcount 为 0,您将通过添加一行来看到这一点,并indexPath.row通过确保在indexPath.row需要之前返回 phatom 单元值来处理任何进一步的调用(如果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
}
Run Code Online (Sandbox Code Playgroud)