Próbuję przewinąć do dołu UITableView po zakończeniu działania [self.tableView reloadData]
Pierwotnie miałem
[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];
Ale potem przeczytałem, że reloadData jest asynchroniczna, więc przewijanie nie następuje od self.tableView
, [self.tableView numberOfSections]
i [self.tableView numberOfRowsinSection
wszystkie mają wartość 0.
Dzięki!
Dziwne jest to, że używam:
[self.tableView reloadData];
NSLog(@"Number of Sections %d", [self.tableView numberOfSections]);
NSLog(@"Number of Rows %d", [self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1);
W konsoli zwraca sekcje = 1, wiersz = -1;
Kiedy robię dokładnie te same NSLogs w cellForRowAtIndexPath
, otrzymuję sekcje = 1 i wiersz = 8; (8 ma rację)
Odpowiedzi:
Przeładowanie ma miejsce podczas następnego przejścia do układu, co zwykle ma miejsce, gdy przywrócisz kontrolę do pętli uruchamiania (po, powiedzmy, akcji przycisku lub cokolwiek innego).
Tak więc jednym ze sposobów uruchomienia czegoś po ponownym załadowaniu widoku tabeli jest po prostu wymuszenie, aby widok tabeli natychmiast wykonał układ:
Innym sposobem jest zaplanowanie późniejszego uruchomienia kodu po układzie za pomocą
dispatch_async
:AKTUALIZACJA
Po dalszych badaniach stwierdzam, że widok tabeli wysyła
tableView:numberOfSections:
itableView:numberOfRowsInSection:
do źródła danych przed powrotem zreloadData
. Jeśli delegat implementujetableView:heightForRowAtIndexPath:
, widok tabeli również wysyła to (dla każdego wiersza) przed powrotem zreloadData
.Jednak widok tabeli nie jest wysyłany
tableView:cellForRowAtIndexPath:
anitableView:headerViewForSection
do fazy układu, co dzieje się domyślnie po przywróceniu sterowania do pętli uruchamiania.Zauważyłem również, że w małym programie testowym kod w pytaniu poprawnie przewija się do dolnej części widoku tabeli, a ja nie robię nic specjalnego (jak wysyłanie
layoutIfNeeded
lub używaniedispatch_async
).źródło
dispatch_async(dispatch_get_main_queue())
nie ma gwarancji, że metoda zadziała. Widzę przy tym niedeterministyczne zachowanie, w którym czasami system ukończył podgląd układu i renderowanie komórki przed blokiem ukończenia, a czasem później. Poniżej zamieszczę odpowiedź, która zadziałała dla mnie.dispatch_async(dispatch_get_main_queue())
nie zawsze działa. Zobacz losowe wyniki tutaj.NSRunLoop
. Pętla uruchomieniowa ma różne fazy i można zaplanować oddzwanianie dla określonej fazy (za pomocą aCFRunLoopObserver
). UIKit planuje rozmieszczenie układów w późniejszej fazie, po powrocie modułu obsługi zdarzeń.Szybki:
Cel C:
źródło
tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
metodę w moim kontrolce widoku próbnego i wstawiając w moim zastąpieniu wszystko, co chciałem powiadomić o zakończeniu przeładowania.Począwszy od Xcode 8.2.1, iOS 10 i swift 3,
Możesz łatwo ustalić koniec
tableView.reloadData()
, używając bloku CATransaction:Powyższe działa również w celu określenia końca reloadData () UICollectionView i reloadAllComponents () UIPickerView.
źródło
beginUpdates
iendUpdates
wywołaniach.setCompletionBlock
moichnumberOfSections
pokazów 2 ... jak dotąd tak dobrze. Ale jeślisetCompletionBlock
zrobiętableView.headerView(forSection: 1)
to w środku , to wracanil
!!! stąd myślę, że ten blok albo dzieje się przed przeładowaniem, albo przechwytuje coś wcześniej, albo robię coś złego. Do Twojej wiadomości spróbowałem odpowiedzi Tylera i zadziałało! @FattiePowyższa
dispatch_async(dispatch_get_main_queue())
metoda nie gwarantuje działania . Widzę przy tym niedeterministyczne zachowanie, w którym czasami system ukończył podgląd układu i renderowanie komórki przed blokiem ukończenia, a czasem później.Oto rozwiązanie, które działa w 100% dla mnie na iOS 10. Wymaga to możliwości utworzenia instancji UITableView lub UICollectionView jako niestandardowej podklasy. Oto rozwiązanie UICollectionView, ale jest dokładnie takie samo dla UITableView:
CustomCollectionView.h:
CustomCollectionView.m:
Przykładowe użycie:
Zobacz tutaj szybką wersję tej odpowiedzi
źródło
layoutSubviews
należy go ustawićnil
jako, że kolejne wywołanialayoutSubviews
, niekoniecznie z powodureloadData
wywołania, spowodują wykonanie bloku, ponieważ utrzymywane jest silne odniesienie, co nie jest pożądanym zachowaniem.reloadDataCompletionBlock
tablicy bloków i iteracja nad nimi po wykonaniu, a następnie opróżnienie tablicy.Miałem te same problemy, co Tyler Sheaffer.
Wdrożyłem jego rozwiązanie w Swift i rozwiązało to moje problemy.
Swift 3.0:
Swift 2:
Przykładowe użycie:
źródło
if let
, mówiąc,reloadDataCompletionBlock?()
że zadzwoni iff nie zero 💥self.reloadDataCompletionBlock? { completion() }
powinno byćself.reloadDataCompletionBlock?()
I
UICollectionView
wersja oparta na odpowiedzi kolaworld:https://stackoverflow.com/a/43162226/1452758
Wymaga testowania. Działa do tej pory na iOS 9.2, Xcode 9.2 beta 2, z przewijaniem kolekcji View do indeksu, jako zamknięcie.
Stosowanie:
źródło
Wygląda na to, że ludzie nadal czytają to pytanie i odpowiedzi. B / c tego, edytuję swoją odpowiedź, aby usunąć słowo Synchronous które jest naprawdę nieistotne dla tego.
When [tableView reloadData]
zwraca, wewnętrzne struktury danych za tableView zostały zaktualizowane. Dlatego po zakończeniu metody możesz bezpiecznie przewinąć na dół. Zweryfikowałem to we własnej aplikacji. Powszechnie akceptowana odpowiedź @ rob-mayoff, choć myląca terminologicznie, potwierdza to samo w swojej ostatniej aktualizacji.Jeśli
tableView
nie przewijasz do dołu, możesz mieć problem z innym kodem, który nie został opublikowany. Być może zmieniasz dane po zakończeniu przewijania i nie ładujesz ponownie i / lub przewijasz do dołu?Dodaj rejestrowanie w następujący sposób, aby sprawdzić, czy dane tabeli są poprawne po
reloadData
. Mam następujący kod w przykładowej aplikacji i działa idealnie.źródło
reloadData
nie jest synchroniczny. Kiedyś - patrz ta odpowiedź: stackoverflow.com/a/16071589/193896reloadData
powrocie.reloadData
. Użyj mojego przypadku testowego,viewWillAppear
aby zaakceptowaćscrollToRowAtIndexPath:
linię b / c, która nie ma znaczenia, jeślitableView
nie jest wyświetlana. Zobaczysz, żereloadData
zaktualizował dane buforowane wtableView
instancji ireloadData
jest synchroniczny. Jeśli odwołujesz się do innychtableView
metod delegowania wywoływanych podczastableView
układania, nie zostaną one wywołane, jeślitableView
nie zostanie wyświetlone. Jeśli nie rozumiem twojego scenariusza, proszę wyjaśnij.Używam tej sztuczki, jestem prawie pewien, że opublikowałem ją już w duplikacie tego pytania:
źródło
Właściwie to rozwiązało mój problem:
źródło
Wypróbuj w ten sposób to zadziała
Wykonam, gdy tabela zostanie całkowicie załadowana
Innym rozwiązaniem jest podklasa UITableView
źródło
Skończyło się na odmianie Shawna:
Utwórz niestandardową klasę UITableView z delegatem:
Następnie w moim kodzie używam
Upewnij się również, że ustawiłeś widok tabeli na CustomTableView w kreatorze interfejsów:
źródło
W Swift 3.0 + możemy stworzyć rozszerzenie do
UITableView
zescaped Closure
jak poniżej:I używaj go jak poniżej, gdziekolwiek chcesz:
mam nadzieję, że to komuś pomoże. Twoje zdrowie!
źródło
Detale
Rozwiązanie
Stosowanie
Pełna próbka
Wyniki
źródło
Aby zaoferować inne podejście, oparte na założeniu, że ukończenie jest „ostatnią widoczną” komórką, do której należy wysłać
cellForRow
.Jednym z możliwych problemów jest: Jeśli
reloadData()
zakończyło się przedlastIndexPathToDisplay
ustawieniem, komórka „ostatnia widoczna” zostanie wyświetlona przedlastIndexPathToDisplay
ustawieniem, a zakończenie nie zostanie wywołane (i będzie w stanie „oczekiwania”):Jeśli cofniemy, możemy zakończyć się wyzwalaniem przez przewijanie wcześniej
reloadData()
.źródło
Spróbuj tego:
Kolor tableView zmieni się z czarnego na zielony dopiero po zakończeniu
reloadData()
funkcji.źródło
Możesz użyć funkcji performBatchUpdates programu uitableview
Oto jak możesz to osiągnąć
źródło
Tworzenie rozszerzenia CATransaction wielokrotnego użytku:
Teraz tworzymy rozszerzenie UITableView, które wykorzystywałoby metodę rozszerzenia CATransaction:
Stosowanie:
źródło
Możesz go użyć do zrobienia czegoś po ponownym załadowaniu danych:
źródło
Spróbuj ustawić opóźnienia:
źródło