Wir machen UITableView. Für Anfänger

Die Neujahrsferien sind vorbei, aber mein Wunsch, nützliche und nicht sehr Artikel zu schreiben - nein! Heute werden wir über UITableView sprechen, mit UITableViewDataSource arbeiten und Zellen wiederverwenden. Wir werden beschreiben, wie der Root-Controller ohne Storyboard installiert wird, Fehler beim Arbeiten mit der Tabelle, dem Layout und einem großen Header für die UINavigationBar .


Für diejenigen, die lustige Witze mögen, habe ich ein Video auf YouTube aufgenommen . Nun, hier wird alles ernst. Fangen wir an.


Erstellen Sie ein leeres Projekt, benennen Sie es nach Belieben und gehen Sie zum Controller. UIKit verfügt über eine UITableViewController- Klasse. Sie können viele Tutorials googeln, in denen die Tabelle genau im Kontext dieser Klasse angezeigt wird. Zum besseren Verständnis werden wir jedoch alles im Basis- UIViewController ausführen .


Wenn eine Tabelle benötigt wird, wird meistens der UINavigationController verwendet:




Fügen wir es hinzu. Fügen Sie in die AppDelegate- Datei mit der Funktion didFinishLaunchingWithOptions den folgenden Code ein:


let navigationController = UINavigationController.init(rootViewController: ViewController()) self.window = UIWindow.init(frame: UIScreen.main.bounds) self.window?.rootViewController = navigationController self.window?.makeKeyAndVisible() 

Ein kurzes Lernprogramm für das Warum: Storeboards und Konstanten sind gut , aber in diesem Tutorial werden wir versuchen, auf sie zu verzichten. Dieser Code ignoriert das Storyboard (Sie können es entfernen) und verpackt den ViewController in den UINavigationController .


Es wäre schön, einen Titel für die UINavigationBar festzulegen . Dazu gehen wir zur ViewController- Klasse (wir werden hier alle weiteren Arbeiten ausführen ) und fügen der viewDidLoad- Methode den folgenden Code hinzu :


 self.view.backgroundColor = UIColor.white self.navigationItem.title = "Table" self.navigationController?.navigationBar.prefersLargeTitles = true 

Jetzt wird der Titel groß und trendy sein. Wenn Sie das Projekt ausführen, sehen Sie Folgendes:




Erstellen einer Tabellenansicht


Die vorbereitenden Maßnahmen sind abgeschlossen, wir können zur Hauptsache übergehen. Erstellen Sie im Controller eine UITableView- Eigenschaft. Wählen Sie einen Initialisierer mit einem Style-Parameter. Stellen Sie einen beliebigen Frame ein, wir werden später darauf zurückkommen. Und für Stil setzen Sie Gruppiert .


 let tableView = UITableView.init(frame: .zero, style: UITableView.Style.grouped) 

Ich habe keine Ahnung, warum dieser Stilname lautet, aber wir können damit eine native Tabelle erstellen, wie in der Anwendung " Einstellungen" . Wenn Sie eine nicht stilisierte Tabelle benötigen, verwenden Sie den Initialisierer nur mit dem Parameter frame.



Layout


Hier wären wir durch die Konstante gerettet worden, aber wir werden nicht nach einfachen Wegen suchen. Ich werde die Methode zeigen, die ich benutze. Natürlich gibt er nicht vor, kanonisch zu sein und muss nicht genau das tun. Wir deklarieren eine Funktion, die den Frame für die Ansichten verfügbar macht, und der Parameter nimmt die Größe des Controllers an:


 private func updateLayout(with size: CGSize) { self.tableView.frame = CGRect.init(origin: .zero, size: size) } 

Sie müssen die Funktion an zwei Stellen aufrufen - in der viewDidLoad- Methode und in viewWillTransition :


 override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) coordinator.animate(alongsideTransition: { (contex) in self.updateLayout(with: size) }, completion: nil) } 

Jetzt wird die Tabelle für jede Ausrichtung im Vollbildmodus platziert. Sie können der updateLayout- Methode eine andere Verarbeitung hinzufügen .


Erstellen einer UITableViewCell


Da es im Tutorial nicht um Zellen, sondern um eine Tabelle geht, werden wir uns nicht im Detail mit der Anpassung befassen. Lassen Sie uns eine von der Basis geerbte Zellklasse erstellen:


 class TableViewCell: UITableViewCell { } 

Um die Zelle in der Tabelle zu verwenden, müssen Sie die Klasse registrieren. Rufen Sie dazu im ViewController die folgende Methode für die Tabelle auf:


 self.tableView.register(TableViewCell.self, forCellReuseIdentifier: "TableViewCell") 

Wenn die Klasse klar ist, verdient der Bezeichner Aufmerksamkeit. In 99% der Fälle funktioniert die Regel:


  • " Zellen derselben Klasse müssen dieselbe Kennung haben "

Es gibt nur sehr wenige Situationen, in denen Zellen derselben Klasse unterschiedliche Bezeichner benötigen, und sie sind hauptsächlich mit dem Rendern und Animieren von Code verbunden .


Datenquelle


Dies ist eine Eigenschaft, die auf das Objekt verweist, das die Tabelle ausfüllt. Das heißt, Implementieren Sie das UITableViewDataSource- Protokoll. Es sind zwei Methoden erforderlich:


 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {} func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {} 

Der erste ist für die Anzahl der Zellen im Abschnitt verantwortlich. Wir haben noch einen Abschnitt, einen Mehrabschnitt (gibt es so ein Wort?), Den wir nicht berücksichtigen werden. Die zweite Methode besteht darin, das Zellenobjekt abzurufen. Es funktioniert gerissen, glaube nicht, dass du einen Kämpfer gebissen hast!


Aber zuerst fügen wir ein Array von Zeilen hinzu, die die Tabelle füllen.



Fahren wir nun mit der Implementierung der ersten Methode fort:


 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { switch tableView { case self.tableView: return self.data.count default: return 0 } } 

Wir teilen der Tabelle mit, dass im 0. Abschnitt so viele Zellen vorhanden sind, wie Elemente im Datenarray vorhanden sind. Die zweite Methode ist etwas komplizierter. Es ist unmöglich, die Zelle einfach zu initialisieren, und das alles aufgrund des Systems der Wiederverwendung von Zellen. Aber keine Notwendigkeit, Apple zu schelten, eigentlich ist es gut! Um das Objekt zu erhalten, müssen Sie den folgenden Code aufrufen:


 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = self.tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell cell.textLabel?.text = self.data[indexPath.row] return cell } 

Die Methode dequeueReusableCell empfängt das Zellenobjekt anhand eines Bezeichners, und wir werden eine Typumwandlung unter Verwendung der TableViewCell- Klasse durchführen, die die Zelle sein sollte. textLabel ist eine Basisklasseneigenschaft, für die keine zusätzliche Konfiguration erforderlich ist.


Die dataSource für die Tabelle muss noch angegeben werden, und die viewDidLoad- Methode sollte nun folgendermaßen aussehen:


 override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = UIColor.white self.navigationItem.title = "Table" self.navigationController?.navigationBar.prefersLargeTitles = true self.view.addSubview(self.tableView) self.tableView.register(TableViewCell.self, forCellReuseIdentifier: "TableViewCell") self.tableView.dataSource = self self.updateLayout(with: self.view.frame.size) } 

Wenn wir das Projekt ausführen, wird eine Tabelle mit Inhalten angezeigt:




Wiederverwendung


Bisher scheint alles in Ordnung zu sein. Fügen wir einen DisclosureIndicator für eine der Zellen hinzu. Dies ist ein Zubehör, das Sie definitiv in iOS gesehen haben:



Angenommen, die Aufgabe besteht darin, den Indikator nur für die erste Zelle zu setzen. Das erste, was mir in den Sinn kommt, ist das Hinzufügen eines einfachen if zur cellForRowAt- Methode:


 if indexPath.row == 0 { cell.accessoryType = .disclosureIndicator } 

Aber der Feind versteckt sich! Lassen Sie uns das Projekt ausführen und die Tabelle vom Bildschirm scrollen:



Der Indikator erschien zum ersten Mal, erscheint aber zufällig für andere Zellen! Dies ist eine Wiederverwendung - es wird eine Zelle verwendet, die im Speicher bequemer ist (eine gute Erklärung für Anfänger, oder?) Und entsprechend der Methode konfiguriert. Manchmal kommt es vor, dass eine Zelle mit einem Indikator gezogen wird. Infolgedessen haben wir einen solchen Fehler. Was zu tun ist?


Alles ist einfach. Es gibt zwei mögliche Lösungen. Der erste befindet sich im else-Block und impliziert im Wesentlichen die eindeutige Konfiguration einer Zelle. Die Methode sieht folgendermaßen aus:


 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = self.tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell cell.textLabel?.text = self.data[indexPath.row] if indexPath.row == 0 { cell.accessoryType = .disclosureIndicator } else { cell.accessoryType = .none } return cell } 

Es gibt noch eine andere Möglichkeit: die Methode prepareForReuse in der Zelle zu implementieren. Wie der Name schon sagt, wird die Methode vor der Wiederverwendung aufgerufen. Sie müssen lediglich die Zelle auf die Standardeinstellungen zurücksetzen. Der Code sieht folgendermaßen aus:


 class TableViewCell: UITableViewCell { override func prepareForReuse() { super.prepareForReuse() self.accessoryType = .none } } 

Mit der Wiederverwendung sind viele Nuancen verbunden. Zum Beispiel die Aufgabe, Bilder für eine Zelle im Hintergrund mit Paginierung, adaptiver Höhe, animiertem Löschen und Einfügen zu laden. Aber mehr dazu im zweiten Teil, wenn meine Hände reichen)


Für Suchende


Ich versuche regelmäßig ein Tutorial auf meinem Kanal aufzunehmen . In diesem Artikel finden Sie Videos zum Zeichnen von Code oder zum Erstellen eines Apple Music Player-Controllers sowie ein Video:


Source: https://habr.com/ru/post/de436390/


All Articles