web-dev-qa-db-fra.com

Sections réductibles: [Assert] Impossible de déterminer le nouvel index de ligne global pour preReloadFirstVisibleRow (0)

J'implémente des en-têtes de section réductibles dans un UITableViewController.

Voici comment je détermine le nombre de lignes à afficher par section:

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

Il y a une structure qui contient les informations de section avec un booléen pour 'isCollapsed'.

Voici comment je bascule leurs états:

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()
}

Tout fonctionne et s'anime bien, mais dans la console lors du repli d'une section développée, j'obtiens ceci [Assert]:

[Assert] Impossible de déterminer le nouvel index de ligne global pour preReloadFirstVisibleRow (0)

Cela se produit, qu'il s'agisse de la même section ouverte, de la fermeture (réduction) ou si j'ouvre une autre section et que je ferme automatiquement la section précédemment ouverte.

Je ne fais rien avec les données; c'est persistant.

Quelqu'un pourrait-il aider à expliquer ce qui manque? Merci

9

Pour qu'une tableView sache où elle se trouve lorsqu'elle recharge des lignes, etc., elle essaie de trouver une "ligne d'ancrage" qu'elle utilise comme référence. C'est ce qu'on appelle un preReloadFirstVisibleRow. Étant donné que cette tableView peut ne pas avoir de lignes visibles à un moment donné en raison de la réduction de toutes les sections, la tableView sera confuse car elle ne peut pas trouver d'ancre. Il sera ensuite réinitialisé au sommet.

Solution: Ajoutez une ligne de hauteur 0 à chaque groupe qui est réduit. De cette façon, même si une section est réduite, il y a toujours une ligne présente (bien que de 0px de hauteur). La tableView a alors toujours quelque chose à laquelle se connecter comme référence. Vous verrez cela en effet par l'ajout d'une ligne dans numberOfRowsInSection si le nombre de lignes est 0 et la gestion de tout indexPath.row appelle en s'assurant de renvoyer la valeur de la cellule phatom avant indexPath.row est nécessaire si le datasource.visibleRows est 0.

Il est plus facile de faire une démonstration dans le code:

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
}
6
Byron Coetsee