Untuk mengetahui kapan tampilan tabel selesai memuat kontennya, pertama-tama kita harus memiliki pemahaman dasar tentang bagaimana tampilan ditampilkan di layar.
Dalam siklus hidup suatu aplikasi, ada 4 momen kunci:
- Aplikasi menerima acara (sentuh, timer, blok dikirim dll)
- Aplikasi ini menangani acara (memodifikasi kendala, memulai animasi, mengubah latar belakang dll)
- Aplikasi menghitung hierarki tampilan baru
- Aplikasi merender hierarki tampilan dan menampilkannya
Waktu 2 dan 3 benar-benar terpisah. MengapaUntuk alasan kinerja, kami tidak ingin melakukan semua perhitungan saat 3 setiap kali modifikasi dilakukan.
Jadi, saya pikir Anda menghadapi kasus seperti ini:
tableView.reloadData()
tableView.visibleCells.count // wrong count oO
Ada apa di sini?
Seperti tampilan apa pun, tampilan tabel memuat ulang kontennya dengan malas. Sebenarnya, jika Anda menelepon reloadData
berkali-kali tidak akan menimbulkan masalah kinerja. Tampilan tabel hanya menghitung ulang ukuran kontennya berdasarkan implementasi delegasinya dan menunggu saat 3 untuk memuat sel-selnya. Kali ini disebut tata letak pass.
Oke, bagaimana cara masuk ke tata letak lulus?
Selama pass tata letak, aplikasi menghitung semua bingkai hierarki tampilan. Untuk terlibat, Anda dapat mengganti metode khusus layoutSubviews
, updateLayoutConstraints
dll dalam a UIView
dan metode yang setara dalam subkelas pengontrol tampilan.
Itulah yang dilakukan tampilan tabel. Ini menimpa layoutSubviews
dan berdasarkan pada implementasi delegasi Anda menambah atau menghapus sel. Itu panggilan cellForRow
tepat sebelum menambahkan dan meletakkan sel baru, willDisplay
tepat setelah. Jika Anda menelepon reloadData
atau baru saja menambahkan tampilan tabel ke hierarki, tampilan tabel menambahkan sebanyak mungkin sel untuk mengisi bingkai pada saat penting ini.
Baiklah, tapi sekarang, bagaimana cara mengetahui kapan tampilan tabel selesai memuat ulang isinya?
Kita sekarang dapat mengulangi pertanyaan ini: bagaimana cara mengetahui kapan tampilan tabel telah selesai menyusun subview?
• Cara termudah adalah masuk ke tata letak tampilan tabel:
class MyTableView: UITableView {
func layoutSubviews() {
super.layoutSubviews()
// the displayed cells are loaded
}
}
Perhatikan bahwa metode ini dipanggil beberapa kali dalam siklus hidup tampilan tabel. Karena gulir dan perilaku dequeue dari tampilan tabel, sel-sel dimodifikasi, dihapus dan sering ditambahkan. Tapi itu berhasil, tepat setelah super.layoutSubviews()
sel-sel dimuat. Solusi ini setara dengan menunggu willDisplay
acara jalur indeks terakhir. Acara ini disebut selama pelaksanaanlayoutSubviews
tampilan tabel untuk setiap sel yang ditambahkan.
• Cara lain adalah dipanggil ketika aplikasi menyelesaikan pass tata letak.
Seperti yang dijelaskan dalam dokumentasi , Anda dapat menggunakan opsi dari UIView.animate(withDuration:completion)
:
tableView.reloadData()
UIView.animate(withDuration: 0) {
// layout done
}
Solusi ini berfungsi tetapi layar akan menyegarkan sekali antara waktu tata letak selesai dan waktu blok dipanggil. Ini setara dengan DispatchMain.async
solusi tetapi ditentukan.
• Atau, saya lebih suka memaksakan tata letak tampilan tabel
Ada metode khusus untuk memaksa tampilan apa pun untuk segera menghitung frame subview-nya layoutIfNeeded
:
tableView.reloadData()
table.layoutIfNeeded()
// layout done
Namun hati-hati, hal itu akan menghapus pemuatan malas yang digunakan oleh sistem. Memanggil metode itu berulang kali dapat menciptakan masalah kinerja. Pastikan mereka tidak akan dipanggil sebelum bingkai tampilan tabel dihitung, jika tidak tampilan tabel akan dimuat lagi dan Anda tidak akan diberitahu.
Saya pikir tidak ada solusi yang sempurna. Kelas subkelas dapat menyebabkan trubles. Layout tata letak dimulai dari atas dan pergi ke bawah sehingga tidak mudah untuk mendapatkan pemberitahuan ketika semua tata letak dilakukan. Dan layoutIfNeeded()
dapat membuat masalah kinerja dll. Tetapi mengetahui pilihan-pilihan itu, Anda harus dapat berpikir pada satu alternatif yang sesuai dengan kebutuhan Anda.