Bagian yang Dapat Diciutkan: [Menegaskan] Tidak dapat menentukan indeks baris global baru untuk preReloadFirstVisibleRow (0)

9

Saya menerapkan tajuk bagian yang dapat diciutkan dalam UITableViewController.

Inilah cara saya menentukan berapa banyak baris untuk ditampilkan per bagian:

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

Ada struct yang menyimpan info bagian dengan bool untuk 'isCollapsed'.

Inilah cara saya mengubah status mereka:

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

Semuanya berfungsi dan menjiwai dengan baik, namun di konsol ketika menutup bagian yang diperluas, saya mendapatkan [Tegas] ini:

[Tegaskan] Tidak dapat menentukan indeks baris global baru untuk preReloadFirstVisibleRow (0)

Ini terjadi, terlepas dari apakah itu Bagian yang sama dibuka, ditutup (runtuh), atau jika saya membuka bagian lain dan 'menutup otomatis' bagian yang sebelumnya terbuka.

Saya tidak melakukan apa pun dengan data; itu gigih.

Adakah yang bisa membantu menjelaskan apa yang hilang? Terima kasih

iOSProgrammingIsFun
sumber
Apakah tampilan tabel Anda terdiri dari banyak bagian dan tidak banyak baris aktual?
Byron Coetsee
Apakah Anda pernah berhasil memperbaikinya?
PaulDoesDev
@ByronCoetsee Ya, sampai bagian diperluas. Jadi ketika semua runtuh itu hanya bagian header. Ketika satu diperluas, itu semua header bagian untuk bagian yang tidak diperluas dan header bagian dan kemudian sel untuk data.
iOSProgrammingIsFun
@ PaulDoesDev saya lakukan, tetapi tidak dengan menggunakan mekanisme ini. Saya benar-benar menulis ulang sehingga sementara tampak sama, ia bekerja dengan sangat berbeda. Namun saya akan meninggalkan ini di sini kalau-kalau seseorang dapat memperbaiki ini dengan elegan, atau itu membantu orang lain dalam beberapa cara.
iOSProgrammingIsFun
1
@ iOSProgrammingIsFun haha ​​ya saya pikir itu mungkin terasa seperti hack dan secara teknis, tetapi jumlah kode dan fakta bahwa itu sebenarnya cukup bersih berarti saya dapat membiarkan diri saya tidur di malam hari: kode P diposting di bawah ini
Byron Coetsee

Jawaban:

8

Agar tableView tahu di mana ia berada saat memuat ulang baris, dll, ia mencoba menemukan "jangkar baris" yang digunakannya sebagai referensi. Ini disebut a preReloadFirstVisibleRow. Karena tableView ini mungkin tidak memiliki baris yang terlihat di beberapa titik karena semua bagian yang diciutkan, tableView akan menjadi bingung karena tidak dapat menemukan jangkar. Kemudian akan diatur ulang ke atas.

Solusi: Tambahkan baris ketinggian 0 untuk setiap grup yang diciutkan. Dengan begitu, bahkan jika suatu bagian diciutkan, masih ada hadiah baris (walaupun tinggi 0px). TableView kemudian selalu memiliki sesuatu untuk dihubungkan sebagai referensi. Anda akan melihat ini berlaku dengan menambahkan baris numberOfRowsInSectionjika jumlah baris 0 dan menangani indexPath.rowpanggilan lebih lanjut dengan memastikan untuk mengembalikan nilai sel phatom sebelum indexPath.rowdiperlukan jika datasource.visibleRows0.

Lebih mudah untuk demo dalam kode:

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