Sezioni comprimibili: [Asser] Impossibile determinare il nuovo indice di riga globale per preReloadFirstVisibleRow (0)


9

Sto implementando le intestazioni di sezione comprimibili in un UITableViewController.

Ecco come determino quante righe mostrare per sezione:

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

C'è una struttura che contiene le informazioni della sezione con un bool per 'isCollapsed'.

Ecco come sto commutando i loro stati:

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

Tutto sta funzionando e animando bene, tuttavia nella console quando si comprime una sezione espansa, ottengo questo [Assert]:

[Assert] Impossibile determinare il nuovo indice di riga globale per preReloadFirstVisibleRow (0)

Ciò accade, indipendentemente dal fatto che si tratti della stessa sezione aperta, di chiusura (compressione) o se sto aprendo un'altra sezione e 'chiudendo automaticamente' la sezione precedentemente aperta.

Non sto facendo nulla con i dati; è persistente.

Qualcuno potrebbe aiutare a spiegare cosa manca? Grazie


Il tuo tableview è composto da un mucchio di sezioni e non molte righe effettive?
Byron Coetsee,

Sei mai riuscito a risolvere questo problema?
PaulDoesDev

@ByronCoetsee Sì, fino a quando una sezione non viene espansa. Quindi, quando tutto è crollato, sono solo le intestazioni di sezione. Quando uno viene espanso, vengono visualizzate tutte le intestazioni di sezione per le sezioni non espanse e un'intestazione di sezione, quindi le celle per i dati.
iOSProgrammingIs Fun

@PaulDoesDev l'ho fatto, ma non usando questo meccanismo. L'ho riscritto completamente in modo che, sebbene appaia uguale, funzioni in modo completamente diverso. Comunque lo lascerò qui nel caso qualcuno riesca a risolverlo elegantemente o aiuti gli altri in qualche modo.
iOSProgrammingIs Fun

1
@iOSProgrammingIsFun haha ​​yeah, ho pensato che potesse sembrare un hack e tecnicamente lo è, ma la quantità di codice e il fatto che sia in realtà abbastanza pulito significa che posso farmi dormire la notte: codice P pubblicato di seguito
Byron Coetsee

Risposte:


8

Affinché un tableView sappia dove si trova mentre sta ricaricando le righe ecc., Cerca di trovare una "riga di ancoraggio" che utilizza come riferimento. Questo si chiama a preReloadFirstVisibleRow. Poiché tableView potrebbe non avere righe visibili a un certo punto a causa della compressione di tutte le sezioni, tableView verrà confuso poiché non riesce a trovare un ancoraggio. Quindi verrà ripristinato all'inizio.

Soluzione: aggiungere una riga di altezza 0 a ogni gruppo compresso. In questo modo, anche se una sezione è crollata, c'è ancora una riga presente (anche se di altezza 0px). TableView ha quindi sempre qualcosa da agganciare come riferimento. Lo vedrai in effetti aggiungendo una riga numberOfRowsInSectionse il conteggio delle righe è 0 e gestendo eventuali ulteriori indexPath.rowchiamate assicurandosi di restituire il valore della cella phatom prima che indexPath.rowsia necessario se datasource.visibleRowsè 0.

Demo nel codice è più semplice:

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
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.