Ich möchte den Versatz der Tabelle ändern, wenn das Laden beendet ist und dieser Versatz von der Anzahl der in die Tabelle geladenen Zellen abhängt.
Ist es im SDK überhaupt zu wissen, wann das Laden einer geeigneten Ansicht abgeschlossen ist? Ich sehe weder auf Delegaten- noch auf Datenquellenprotokollen etwas.
Ich kann die Anzahl der Datenquellen nicht verwenden, da nur die sichtbaren Zellen geladen werden.
ios
iphone
uitableview
emenegro
quelle
quelle
Antworten:
Verbessere auf @RichX Antwort:
lastRow
kann beides sein[tableView numberOfRowsInSection: 0] - 1
oder((NSIndexPath*)[[tableView indexPathsForVisibleRows] lastObject]).row
. Der Code lautet also:UPDATE: Nun, @ htafoyas Kommentar ist richtig. Wenn Sie möchten, dass dieser Code das Ende des Ladens aller Daten aus der Quelle erkennt, wird dies nicht der Fall sein, aber das ist nicht die ursprüngliche Frage. Dieser Code dient zum Erkennen, wann alle Zellen angezeigt werden, die sichtbar sein sollen.
willDisplayCell:
Wird hier für eine flüssigere Benutzeroberfläche verwendet (einzelne Zellen werden normalerweise nach demwillDisplay:
Anruf schnell angezeigt ). Sie können es auch mit versuchentableView:didEndDisplayingCell:
.quelle
viewForFooterInSection
Methode.Schnelle 3 & 4 & 5 Version:
quelle
Ich benutze immer diese sehr einfache Lösung:
quelle
[tableView numberOfRowsInSection: 0] - 1
. Sie müssen0
durch den erforderlichen Wert ersetzen . Das ist aber nicht das Problem. Problem ist, dass UITableView nur sichtbar lädt. Allerdings((NSIndexPath*)[[tableView indexPathsForVisibleRows] lastObject]).row
löst das Problem.Hier ist eine weitere Option, die für mich zu funktionieren scheint. Überprüfen Sie in der viewForFooter-Delegatmethode, ob es sich um den letzten Abschnitt handelt, und fügen Sie dort Ihren Code hinzu. Dieser Ansatz kam mir in den Sinn, nachdem festgestellt wurde, dass willDisplayCell keine Fußzeilen berücksichtigt, wenn Sie diese haben.
Ich finde, dieser Ansatz funktioniert am besten, wenn Sie die Endbelastung für die gesamte
UITableView
und nicht nur für die sichtbaren Zellen ermitteln möchten. Abhängig von Ihren Anforderungen möchten Sie möglicherweise nur die sichtbaren Zellen. In diesem Fall ist die Antwort von folex ein guter Weg.quelle
nil
vontableView:viewForFooterInSection:
meinem Layout in iOS 7 mit Auto Layout durcheinander.return CGRectMake(0,0,0,0);
self.tableView.sectionFooterHeight = 0
. In beiden Fällen scheint eine Fußzeile mit einer Höhe von etwa 10 eingefügt zu werden. Ich wette, ich könnte dies beheben, indem ich der zurückgegebenen Ansicht eine Einschränkung mit einer Höhe von 0 hinzufüge. Wie auch immer, ich bin gut, weil ich eigentlich herausfinden wollte, wie UITableView in der letzten Zelle gestartet wird, aber dies zuerst gesehen habe.Swift 2-Lösung:
quelle
Private API verwenden:
Öffentliche API verwenden:
Ein mögliches besseres Design besteht darin, die sichtbaren Zellen zu einem Satz hinzuzufügen. Wenn Sie dann überprüfen müssen, ob die Tabelle geladen ist, können Sie stattdessen eine for-Schleife um diesen Satz durchführen, z
quelle
Für die gewählte Antwortversion in Swift 3:
Ich brauchte die Variable isLoadingTableView, weil ich sicherstellen wollte, dass die Tabelle vollständig geladen ist, bevor ich eine Standardzellenauswahl vornehme. Wenn Sie dies nicht einschließen, wird Ihr Code jedes Mal, wenn Sie durch die Tabelle scrollen, erneut aufgerufen.
quelle
Der beste Ansatz, den ich kenne, ist Erics Antwort unter: Benachrichtigt werden, wenn UITableView die Datenanfrage beendet hat?
Update: Damit es funktioniert, muss ich diese Anrufe tätigen
-tableView:cellForRowAtIndexPath:
quelle
Um zu wissen, wann eine Tabellenansicht den Inhalt vollständig geladen hat, müssen wir zunächst ein grundlegendes Verständnis dafür haben, wie die Ansichten auf dem Bildschirm angezeigt werden.
Im Lebenszyklus einer App gibt es 4 Schlüsselmomente:
Die 2 und 3 Zeiten sind völlig getrennt. Warum ? Aus Leistungsgründen möchten wir nicht jedes Mal, wenn eine Änderung vorgenommen wird, alle Berechnungen des Augenblicks 3 durchführen.
Ich denke, Sie stehen vor einem Fall wie diesem:
Was ist hier los?
Wie jede Ansicht lädt eine Tabellenansicht ihren Inhalt träge neu. Wenn Sie
reloadData
mehrmals anrufen , entstehen keine Leistungsprobleme. Die Tabellenansicht berechnet nur die Inhaltsgröße basierend auf der Delegatenimplementierung neu und wartet im Moment 3, bis die Zellen geladen sind. Diese Zeit wird als Layout-Pass bezeichnet.Okay, wie komme ich in den Layout-Pass?
Während des Layoutdurchlaufs berechnet die App alle Frames der Ansichtshierarchie. Sich zu engagieren, können Sie die speziellen Methoden außer Kraft setzen
layoutSubviews
,updateLayoutConstraints
usw. in einUIView
und die entsprechenden Methoden in einer View - Controller - Unterklasse.Genau das macht eine Tabellenansicht. Es überschreibt
layoutSubviews
und basierend auf Ihrer Delegatenimplementierung werden Zellen hinzugefügt oder entfernt. Es wirdcellForRow
direkt vor dem Hinzufügen und Auslegen einer neuen ZellewillDisplay
aufgerufen. Wenn SiereloadData
die Tabellenansicht aufgerufen oder nur der Hierarchie hinzugefügt haben, fügt die Tabellenansicht so viele Zellen hinzu, wie erforderlich sind, um den Rahmen in diesem Schlüsselmoment zu füllen.Okay, aber jetzt wissen Sie, wann eine Tabellenansicht ihren Inhalt neu geladen hat.
Wir können jetzt diese Frage umformulieren: Woher wissen, wann eine Tabellenansicht ihre Unteransichten fertig angelegt hat?
• Der einfachste Weg ist, in das Layout der Tabellenansicht zu gelangen:
Beachten Sie, dass diese Methode im Lebenszyklus der Tabellenansicht häufig aufgerufen wird. Aufgrund des Bildlaufs und des Warteschlangenverhaltens der Tabellenansicht werden Zellen häufig geändert, entfernt und hinzugefügt. Aber es funktioniert direkt nach dem
super.layoutSubviews()
Laden der Zellen. Diese Lösung entspricht dem Warten auf daswillDisplay
Ereignis des letzten Indexpfads. Dieses Ereignis wird während der AusführunglayoutSubviews
der Tabellenansicht für jede hinzugefügte Zelle aufgerufen .• Eine andere Möglichkeit besteht darin, aufgerufen zu werden, wenn die App einen Layoutdurchlauf abgeschlossen hat.
Wie in der Dokumentation beschrieben , können Sie eine der folgenden Optionen verwenden
UIView.animate(withDuration:completion)
:Diese Lösung funktioniert, aber der Bildschirm wird zwischen dem Zeitpunkt des Layouts und dem Zeitpunkt, zu dem der Block aufgerufen wird, einmal aktualisiert. Dies entspricht der
DispatchMain.async
Lösung, ist jedoch angegeben.• Alternativ würde ich es vorziehen, das Layout der Tabellenansicht zu erzwingen
Es gibt eine spezielle Methode, um jede Ansicht zu zwingen, ihre Unteransichtsrahmen sofort zu berechnen
layoutIfNeeded
:Seien Sie jedoch vorsichtig, da dadurch die vom System verwendete verzögerte Belastung beseitigt wird. Das wiederholte Aufrufen dieser Methoden kann zu Leistungsproblemen führen. Stellen Sie sicher, dass sie nicht aufgerufen werden, bevor der Rahmen der Tabellenansicht berechnet wird. Andernfalls wird die Tabellenansicht erneut geladen und Sie werden nicht benachrichtigt.
Ich denke, es gibt keine perfekte Lösung. Unterklassen können zu Problemen führen. Ein Layout-Durchgang beginnt von oben nach unten, sodass es nicht einfach ist, benachrichtigt zu werden, wenn das gesamte Layout fertig ist. Und
layoutIfNeeded()
könnte Leistungsprobleme usw. verursachen. Wenn Sie diese Optionen kennen, sollten Sie in der Lage sein, eine Alternative zu finden, die Ihren Anforderungen entspricht.quelle
So geht's in Swift 3:
quelle
Hier ist, wie ich es in Swift 3 mache
quelle
Hier ist was ich tun würde.
In Ihrer Basisklasse (kann rootVC BaseVc usw. sein),
A. Schreiben Sie ein Protokoll, um den Rückruf "DidFinishReloading" zu senden.
B. Schreiben Sie eine generische Methode, um die Tabellenansicht neu zu laden.
Rufen Sie in der Implementierung der Basisklassenmethode reloadData auf, gefolgt von delegateMethod mit Verzögerung.
Bestätigen Sie das Reload-Abschlussprotokoll in allen View-Controllern, in denen Sie den Rückruf benötigen.
Referenz: https://discussions.apple.com/thread/2598339?start=0&tstart=0
quelle
@folex Antwort ist richtig.
Es schlägt jedoch fehl, wenn in tableView mehr als ein Abschnitt gleichzeitig angezeigt wird.
quelle
In Swift können Sie so etwas tun. Die folgende Bedingung gilt jedes Mal, wenn Sie das Ende der Tabellenansicht erreichen
quelle
Ich weiß, dass dies beantwortet wird, ich füge nur eine Empfehlung hinzu.
Gemäß der folgenden Dokumentation
https://www.objc.io/issues/2-concurrency/thread-safe-class-design/
Das Beheben von Zeitproblemen mit dispatch_async ist eine schlechte Idee. Ich schlage vor, wir sollten dies durch Hinzufügen von FLAG oder so behandeln.
quelle
Wenn Sie mehrere Abschnitte haben, erhalten Sie folgende Informationen zum Abrufen der letzten Zeile im letzten Abschnitt (Swift 3):
quelle
Ganz zufällig bin ich auf diese Lösung gestoßen:
Sie müssen die Fußzeile einstellen, bevor Sie die contentSize abrufen können, z. B. in viewDidLoad. Übrigens. Durch Einstellen von footeView können Sie "nicht verwendete" Trennzeichen löschen
quelle
Suchen Sie nach der Gesamtzahl der Elemente, die in der Tabelle angezeigt werden, oder nach der Gesamtzahl der aktuell sichtbaren Elemente? So oder so. Ich glaube, dass die 'viewDidLoad'-Methode ausgeführt wird, nachdem alle Datenquellenmethoden aufgerufen wurden. Dies funktioniert jedoch nur beim ersten Laden der Daten (wenn Sie einen einzelnen ViewController zuweisen).
quelle
Ich kopiere Andrews Code und erweitere ihn, um den Fall zu berücksichtigen, dass Sie nur 1 Zeile in der Tabelle haben. Es funktioniert soweit für mich!
HINWEIS: Ich verwende nur einen Abschnitt aus Andrews Code. Denken Sie also daran.
quelle
In iOS7.0x ist die Lösung etwas anders. Folgendes habe ich mir ausgedacht.
quelle
Ziel c
Schnell
quelle
UICollectionView
.