折りたたみ可能なセクション:[アサート] preReloadFirstVisibleRow(0)の新しいグローバル行インデックスを特定できません


9

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)の新しいグローバル行インデックスを特定できません

これは、開いているセクションが同じであるか、閉じている(折りたたまれている)か、別のセクションを開いて以前開いていたセクションを「自動閉じる」かどうかに関係なく発生します。

データについては何もしていません。それは永続的です。

誰が不足しているものを説明するのを手伝ってくれる?ありがとう


テーブルビューはたくさんのセクションで構成されており、実際の行は多くありませんか?
Byron Coetsee

これをなんとか修正したことがありますか?
PaulDoesDev

@ByronCoetseeはい、セクションが展開されるまで。つまり、すべてが折りたたまれているときは、セクションヘッダーだけです。1つが展開されると、展開されていないセクションのすべてのセクションヘッダーとセクションヘッダー、そしてデータのセルになります。
iOSProgrammingIsFun

@PaulDoesDev私はそうしましたが、このメカニズムを使用したわけではありません。私はそれを完全に書き直したので、同じように見えても、まったく異なる動作をします。ただし、誰かがエレガントにこれを修正できる場合、または何らかの方法で他の人を助ける場合に備えて、これはここに残しておきます。
iOSProgrammingIsFun

1
@iOSProgrammingIsFun笑ええ、私はそれはハックのように感じることがあり、それは技術的にですが、コードの量と、それは私自身が夜眠ることができ、実際にはかなりきれいな手段だという事実考えた:Pコードは以下の投稿
バイロンCoetsee

回答:


8

tableViewが行の再読み込み中などにそれがどこにあるかを知るために、参照として使用する「アンカー行」を見つけようとします。これはと呼ばれますpreReloadFirstVisibleRow。すべてのセクションが折りたたまれているために、このtableViewには表示されている行がない場合があるため、tableViewはアンカーを見つけられないため混乱します。その後、上部にリセットされます。

解決策: 折りたたまれているすべてのグループに高さ0の行を追加します。そうすれば、セクションが折りたたまれていても、行が存在します(高さが0pxです)。その場合、tableViewには常に参照としてフックするものがあります。これはnumberOfRowsInSection、rowcountが0の場合に行を追加し、0の場合に必要になるindexPath.row前にフェイトセルの値を返すことを確実にすることにより、それ以降の呼び出しを処理することでindexPath.row有効になりdatasource.visibleRowsます。

コードでデモする方が簡単です。

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
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.