Les vacances du Nouvel An sont passées, mais mon envie d'écrire des articles utiles et pas très - non! Aujourd'hui, nous allons parler d' UITableView , travailler avec UITableViewDataSource et réutiliser des cellules. Nous verrons comment installer le contrôleur racine sans storyboard, les erreurs lors de l'utilisation de la table, la mise en page et un grand en-tête pour UINavigationBar .
Pour ceux qui aiment les blagues drôles, j'ai enregistré une vidéo sur YouTube . Eh bien, ici, tout sera sérieux. Commençons.
Créez un projet vide, nommez-le comme vous le souhaitez et accédez au contrôleur. UIKit a une classe UITableViewController . Vous pouvez google de nombreux tutoriels où le tableau est affiché exactement dans le contexte de cette classe. Mais pour une meilleure compréhension, nous ferons tout dans la base UIViewController .
Le plus souvent, lorsqu'une table est nécessaire, l' UINavigationController est utilisé:

Ajoutons-le. Dans le fichier AppDelegate , la fonction didFinishLaunchingWithOptions , insérez le code suivant:
let navigationController = UINavigationController.init(rootViewController: ViewController()) self.window = UIWindow.init(frame: UIScreen.main.bounds) self.window?.rootViewController = navigationController self.window?.makeKeyAndVisible()
Un petit programme éducatif expliquant pourquoi: les tableaux d'affichage et les constantes sont bons , mais dans ce didacticiel, nous allons essayer de nous en passer. Ce code ignorera le storyboard (vous pouvez le supprimer) et encapsulera le ViewController dans le UINavigationController .
Ce serait bien de définir un titre pour UINavigationBar . Pour ce faire, nous irons à la classe ViewController (nous ferons tous les travaux supplémentaires ici) et ajouterons le code suivant à la méthode viewDidLoad :
self.view.backgroundColor = UIColor.white self.navigationItem.title = "Table" self.navigationController?.navigationBar.prefersLargeTitles = true
Maintenant, le titre sera grand et branché. En exécutant le projet, nous verrons ce qui suit:

Créer une TableView
Les actions préparatoires sont terminées, nous pouvons passer à l'essentiel. Dans le contrôleur, créez une propriété UITableView . Choisissez un initialiseur qui a un paramètre Style. Définissez n'importe quel cadre, nous y reviendrons plus tard. Et pour le style, définissez Groupé .
let tableView = UITableView.init(frame: .zero, style: UITableView.Style.grouped)
Je ne sais pas pourquoi ce nom de style est, mais cela nous permettra de créer une table native, comme dans l'application Paramètres . Si vous avez besoin d'une table non stylisée, utilisez l'initialiseur avec le paramètre frame uniquement.

Disposition
Ici, nous aurions été sauvés par la constante, mais nous ne chercherons pas de moyens faciles. Je vais montrer la méthode que j'utilise. Bien sûr, il ne prétend pas être canonique et ce n'est pas nécessaire. Nous déclarons une fonction qui exposera le cadre aux vues, et le paramètre prendra la taille du contrôleur:
private func updateLayout(with size: CGSize) { self.tableView.frame = CGRect.init(origin: .zero, size: size) }
Vous devez appeler la fonction à deux endroits - dans la méthode viewDidLoad et dans 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) }
Maintenant, le tableau pour toute orientation sera placé en plein écran. Vous pouvez ajouter un autre traitement à la méthode updateLayout .
Créer une UITableViewCell
Étant donné que le didacticiel ne concerne pas les cellules, mais un tableau, nous ne nous attarderons pas sur la personnalisation en détail. Faisons une classe de cellules héritée de la base:
class TableViewCell: UITableViewCell { }
Pour utiliser la cellule du tableau, vous devez enregistrer la classe. Pour ce faire, dans le ViewController , appelez la méthode suivante sur la table:
self.tableView.register(TableViewCell.self, forCellReuseIdentifier: "TableViewCell")
Si la classe est claire, alors l'identifiant mérite attention. Dans 99% des cas, la règle fonctionnera:
- " Les cellules de la même classe doivent avoir le même identifiant "
Il existe très peu de situations où les cellules d'une même classe nécessitent des identifiants différents, et elles sont principalement associées au rendu de code et aux animations.
Source de données
Il s'agit d'une propriété qui pointe vers l'objet qui remplira le tableau. C'est-à-dire implémenter le protocole UITableViewDataSource . Deux méthodes sont nécessaires:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {} func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {}
Le premier est responsable du nombre de cellules dans la section. Nous avons encore une section, une multisection (existe-t-il un tel mot?) Nous ne considérerons pas. La deuxième méthode consiste à obtenir l'objet cellule. Cela fonctionne astucieusement, ne pensez pas que vous avez mordu un combattant!
Mais d'abord, ajoutons un tableau de lignes qui remplira le tableau.

Passons maintenant à l'implémentation de la première méthode:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { switch tableView { case self.tableView: return self.data.count default: return 0 } }
Nous indiquons au tableau que dans la section 0, il y aura autant de cellules que d'éléments dans le tableau de données . La deuxième méthode est un peu plus compliquée. Il est impossible d'initialiser simplement la cellule, et tout cela à cause du système de réutilisation des cellules. Mais pas besoin de gronder Apple, en fait c'est bon! Pour obtenir l'objet, vous devez appeler le code suivant:
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 }
La méthode dequeueReusableCell recevra l'objet cellule par identifiant, et nous transtyperons en utilisant type quant à la classe TableViewCell , qui devrait être la cellule. textLabel est une propriété de classe de base; aucune configuration supplémentaire n'est requise.
Il reste à spécifier la source de données pour la table et la méthode viewDidLoad devrait maintenant ressembler à ceci:
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) }
Si nous exécutons le projet, nous verrons un tableau rempli de contenu:

Réutiliser
Jusqu'à présent, tout semble être en ordre. Ajoutons un révélationIndicator pour l'une des cellules. Voici un accessoire que vous avez définitivement vu sur iOS:

Supposons que la tâche consiste à définir l'indicateur uniquement pour la première cellule. La première chose qui me vient à l'esprit est d'ajouter un simple if à la méthode cellForRowAt :
if indexPath.row == 0 { cell.accessoryType = .disclosureIndicator }
Mais l'ennemi se cache! Exécutons le projet et faisons défiler le tableau hors de l'écran:

L'indicateur est apparu pour la première, mais apparaît au hasard pour les autres cellules! C'est une réutilisation - une cellule est prise qui est plus pratique en mémoire (une excellente explication pour les débutants, non?) Et configurée selon la méthode. Parfois, il arrive qu'une cellule avec un indicateur soit tirée. En conséquence, nous avons un tel bug. Que faire
Tout est simple. Il existe deux solutions possibles. Le premier est dans le bloc else et implique essentiellement la configuration non ambiguë de n'importe quelle cellule. La méthode ressemblera à ceci:
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 }
Il existe un autre moyen: implémenter la méthode prepareForReuse sur la cellule. Comme son nom l'indique, la méthode est appelée avant réutilisation. Tout ce que vous devez faire est de réinitialiser la cellule par défaut. Le code ressemble à ceci:
class TableViewCell: UITableViewCell { override func prepareForReuse() { super.prepareForReuse() self.accessoryType = .none } }
Il existe de nombreuses nuances associées à la réutilisation. Par exemple, la tâche de charger des images pour une cellule en arrière-plan avec pagination, hauteur adaptative, suppression et insertion animées. Mais plus à ce sujet dans la deuxième partie, si mes mains atteignent)
Pour les demandeurs
J'essaie d'enregistrer régulièrement un tutoriel sur ma chaîne . Vous pouvez trouver des vidéos sur la façon de dessiner du code ou comment créer un contrôleur de lecteur Apple Music , ainsi qu'une vidéo sur cet article: