Saya mencoba untuk menggulir ke bagian bawah UITableView setelah selesai melakukan [self.tableView reloadData]
Saya awalnya punya
[self.tableView reloadData]
NSIndexPath* indexPath = [NSIndexPath indexPathForRow: ([self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1) inSection: ([self.tableView numberOfSections]-1)];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
Tapi kemudian saya membaca bahwa reloadData asynchronous, sehingga scrolling tidak terjadi sejak self.tableView
, [self.tableView numberOfSections]
dan [self.tableView numberOfRowsinSection
semuanya 0.
Terima kasih!
Yang aneh adalah saya menggunakan:
[self.tableView reloadData];
NSLog(@"Number of Sections %d", [self.tableView numberOfSections]);
NSLog(@"Number of Rows %d", [self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1);
Di konsol itu mengembalikan Bagian = 1, Baris = -1;
Ketika saya melakukan NSLogs yang sama persis di cellForRowAtIndexPath
saya mendapatkan Bagian = 1 dan Baris = 8; (8 benar)
Jawaban:
Reload terjadi selama pass tata letak berikutnya, yang biasanya terjadi ketika Anda mengembalikan kontrol ke loop dijalankan (setelah, katakanlah, tindakan tombol Anda atau apa pun yang kembali).
Jadi salah satu cara untuk menjalankan sesuatu setelah reload tampilan tabel adalah dengan memaksa tampilan tabel untuk segera melakukan tata letak:
Cara lain adalah dengan menjadwalkan kode after-layout Anda untuk dijalankan nanti menggunakan
dispatch_async
:MEMPERBARUI
Setelah diselidiki lebih lanjut, saya menemukan bahwa tampilan tabel mengirim
tableView:numberOfSections:
dantableView:numberOfRowsInSection:
ke sumber datanya sebelum kembali darireloadData
. Jika delegasi mengimplementasikantableView:heightForRowAtIndexPath:
, tampilan tabel juga mengirimkan itu (untuk setiap baris) sebelum kembali darireloadData
.Namun, tampilan tabel tidak mengirim
tableView:cellForRowAtIndexPath:
atautableView:headerViewForSection
sampai fase tata letak, yang terjadi secara default ketika Anda mengembalikan kontrol ke loop dijalankan.Saya juga menemukan bahwa dalam program uji kecil, kode dalam pertanyaan Anda dengan benar menggulir ke bagian bawah tampilan tabel, tanpa saya melakukan sesuatu yang istimewa (seperti mengirim
layoutIfNeeded
atau menggunakandispatch_async
).sumber
dispatch_async(dispatch_get_main_queue())
metode tidak dijamin untuk bekerja. Saya melihat perilaku non-deterministik dengannya, di mana terkadang sistem telah menyelesaikan layoutSubviews dan rendering sel sebelum blok penyelesaian, dan kadang-kadang setelah itu. Saya akan memposting jawaban yang sesuai untuk saya di bawah ini.dispatch_async(dispatch_get_main_queue())
tidak selalu berhasil. Melihat hasil acak di sini.NSRunLoop
. Run loop memiliki fase yang berbeda, dan Anda dapat menjadwalkan panggilan balik untuk fase tertentu (menggunakan aCFRunLoopObserver
). UIKit menjadwalkan tata letak yang akan terjadi selama fase selanjutnya, setelah event handler Anda kembali.Cepat:
Tujuan-C:
sumber
tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
metode pengontrol tampilan Mock saya dan memasukkan dalam menimpa apa pun yang saya ingin beri tahu bahwa pemuatan ulang telah selesai.Pada Xcode 8.2.1, iOS 10, dan swift 3,
Anda dapat menentukan akhir
tableView.reloadData()
dengan mudah menggunakan blok transaksi CAT:Di atas juga berfungsi untuk menentukan akhir reloadData UICollectionView () dan reload UIPickerView's AllComponents ().
sumber
beginUpdates
danendUpdates
panggilan.setCompletionBlock
sayanumberOfSections
2 ... sejauh ini sangat bagus. Namun jika di dalamsetCompletionBlock
aku melakukannyatableView.headerView(forSection: 1)
kembalinil
!!! maka saya pikir blok ini terjadi sebelum memuat ulang atau menangkap sesuatu sebelum atau saya melakukan sesuatu yang salah. FYI saya sudah mencoba jawaban Tyler dan itu berhasil! @FattieThe
dispatch_async(dispatch_get_main_queue())
Metode di atas tidak dijamin untuk bekerja . Saya melihat perilaku non-deterministik dengannya, di mana kadang-kadang sistem telah menyelesaikan layoutSubviews dan rendering sel sebelum blok penyelesaian, dan kadang-kadang setelah itu.Inilah solusi yang berfungsi 100% untuk saya, di iOS 10. Ini memerlukan kemampuan untuk membuat Instantiate UITableView atau UICollectionView sebagai subkelas kustom. Inilah solusi UICollectionView, tetapi persis sama untuk UITableView:
CustomCollectionView.h:
CustomCollectionView.m:
Contoh penggunaan:
Lihat di sini untuk versi Swift dari jawaban ini
sumber
layoutSubviews
dalamnya harus ditetapkannil
sebagai panggilan berikutnya untuklayoutSubviews
, tidak harus karenareloadData
dipanggil, akan mengakibatkan blok dieksekusi karena ada referensi kuat ditahan, yang bukan perilaku yang diinginkan.reloadDataCompletionBlock
array blok dan mengulanginya pada eksekusi dan mengosongkan array setelah itu.Saya memiliki masalah yang sama dengan Tyler Sheaffer.
Saya menerapkan solusinya di Swift dan itu memecahkan masalah saya.
Swift 3.0:
Swift 2:
Contoh penggunaan:
sumber
if let
dengan mengatakanreloadDataCompletionBlock?()
yang akan memanggil iff not nil 💥self.reloadDataCompletionBlock? { completion() }
seharusnyaself.reloadDataCompletionBlock?()
Dan sebuah
UICollectionView
versi, berdasarkan jawaban kolaworld:https://stackoverflow.com/a/43162226/1452758
Perlu pengujian. Bekerja sejauh ini di iOS 9.2, Xcode 9.2 beta 2, dengan menggulir collectionView ke indeks, sebagai penutup.
Pemakaian:
sumber
Tampaknya orang-orang masih membaca pertanyaan ini dan jawabannya. B / c itu, saya mengedit jawaban saya untuk menghapus kata Synchronous yang benar-benar tidak relevan dengan ini.
When [tableView reloadData]
kembali, struktur data internal di belakang tableView telah diperbarui. Karena itu, ketika metode ini selesai Anda dapat dengan aman gulir ke bawah. Saya memverifikasi ini di aplikasi saya sendiri. Jawaban yang diterima secara luas oleh @ rob-mayoff, sementara juga membingungkan dalam terminologi, mengakui hal yang sama dalam pembaruan terakhirnya.Jika Anda
tableView
tidak menggulir ke bawah, Anda mungkin memiliki masalah dengan kode lain yang belum Anda posting. Mungkin Anda mengubah data setelah gulir selesai dan Anda tidak memuat ulang dan / atau menggulir ke bawah?Tambahkan beberapa logging sebagai berikut untuk memverifikasi bahwa data tabel sudah benar setelah
reloadData
. Saya memiliki kode berikut dalam aplikasi sampel dan berfungsi dengan baik.sumber
reloadData
tidak sinkron. Dulu - lihat jawaban ini: stackoverflow.com/a/16071589/193896reloadData
kembali.reloadData
. Gunakan test case sayaviewWillAppear
untuk menerimascrollToRowAtIndexPath:
baris b / c yang tidak ada artinya jikatableView
tidak ditampilkan. Anda akan melihat bahwareloadData
pembaruan data yang di-cache dalamtableView
contoh dan yangreloadData
sinkron. Jika Anda merujuk padatableView
metode delegasi lain yang dipanggil saattableView
tata letak sedang keluar, mereka tidak akan dipanggil jikatableView
tidak ditampilkan. Jika saya salah memahami skenario Anda, mohon jelaskan.Saya menggunakan trik ini, cukup yakin saya sudah mempostingnya ke duplikat dari pertanyaan ini:
sumber
Sebenarnya yang ini menyelesaikan masalah saya:
sumber
Coba cara ini akan berhasil
Saya akan mengeksekusi ketika tabel sudah dimuat penuh
Solusi lainnya adalah Anda dapat mensubklasifikasikan UITableView
sumber
Saya akhirnya menggunakan variasi solusi Shawn:
Buat kelas UITableView khusus dengan delegasi:
Kemudian dalam kode saya, saya gunakan
Pastikan juga Anda mengatur tampilan tabel Anda ke CustomTableView di pembuat antarmuka:
sumber
Di Swift 3.0 + kita dapat membuat ekstensi untuk
UITableView
denganescaped Closure
seperti di bawah ini:Dan gunakan seperti di bawah ini di mana pun Anda inginkan:
Semoga ini bisa membantu seseorang. Bersulang!
sumber
Detail
Larutan
Pemakaian
Sampel lengkap
Hasil
sumber
Hanya untuk menawarkan pendekatan lain, berdasarkan gagasan penyelesaian menjadi sel 'terakhir terlihat' untuk dikirim
cellForRow
.Salah satu masalah yang mungkin terjadi adalah: Jika
reloadData()
telah selesai sebelumlastIndexPathToDisplay
ditetapkan, sel 'terakhir terlihat' akan ditampilkan sebelumlastIndexPathToDisplay
diatur dan penyelesaian tidak akan dipanggil (dan akan dalam keadaan 'menunggu'):Jika kita mundur, kita bisa berakhir dengan dipicu oleh pengguliran sebelumnya
reloadData()
.sumber
Coba ini:
Warna tableView akan berubah dari hitam menjadi hijau hanya setelah
reloadData()
fungsi selesai.sumber
Anda dapat menggunakan fungsi performBatchUpdates dari uitableview
Inilah cara Anda bisa mencapainya
sumber
Membuat ekstensi CATransaction yang dapat digunakan kembali:
Sekarang membuat ekstensi UITableView yang akan menggunakan metode ekstensi CATransaction:
Pemakaian:
sumber
Anda dapat menggunakannya untuk melakukan sesuatu setelah memuat ulang data:
sumber
Coba atur penundaan:
sumber