Pour savoir quand une vue de tableau termine le chargement de son contenu, nous devons d'abord avoir une compréhension de base de la façon dont les vues sont affichées à l'écran.
Dans le cycle de vie d'une application, il y a 4 moments clés:
- L'application reçoit un événement (tactile, minuterie, bloc distribué, etc.)
- L'application gère l'événement (elle modifie une contrainte, démarre une animation, change l'arrière-plan, etc.)
- L'application calcule la nouvelle hiérarchie de vues
- L'application rend la hiérarchie des vues et l'affiche
Les temps 2 et 3 sont totalement séparés. Pourquoi ? Pour des raisons de performances, nous ne souhaitons pas effectuer tous les calculs du moment 3 à chaque fois qu'une modification est effectuée.
Donc, je pense que vous êtes confronté à un cas comme celui-ci:
tableView.reloadData()
tableView.visibleCells.count // wrong count oO
Quel est le problème ici?
Comme toute vue, une vue de table recharge son contenu paresseusement. En fait, si vous appelez reloadData
plusieurs fois, cela ne créera pas de problèmes de performances. La vue tableau ne recalcule que la taille de son contenu en fonction de son implémentation déléguée et attend le moment 3 pour charger ses cellules. Cette fois, on appelle une passe de mise en page.
Ok, comment entrer dans le pass de mise en page?
Pendant la passe de mise en page, l'application calcule tous les cadres de la hiérarchie de vues. Pour vous impliquer, vous pouvez remplacer les méthodes dédiées layoutSubviews
, updateLayoutConstraints
etc. dans a UIView
et les méthodes équivalentes dans une sous-classe de contrôleur de vue.
C'est exactement ce que fait une vue de table. Il remplace layoutSubviews
et en fonction de votre implémentation de délégué, ajoute ou supprime des cellules. Il appelle cellForRow
juste avant d'ajouter et de disposer une nouvelle cellule, willDisplay
juste après. Si vous avez appelé reloadData
ou simplement ajouté la vue tableau à la hiérarchie, la vue tableaux ajoute autant de cellules que nécessaire pour remplir son cadre à ce moment clé.
D'accord, mais maintenant, comment savoir quand une vue de tableaux a fini de recharger son contenu?
Nous pouvons maintenant reformuler cette question: comment savoir quand une vue de tableau a fini de disposer ses sous-vues?
• Le moyen le plus simple est d'entrer dans la disposition de la vue tableau:
class MyTableView: UITableView {
func layoutSubviews() {
super.layoutSubviews()
// the displayed cells are loaded
}
}
Notez que cette méthode est appelée plusieurs fois dans le cycle de vie de la vue table. En raison du défilement et du comportement de sortie de la file d'attente de la vue tableau, les cellules sont modifiées, supprimées et ajoutées souvent. Mais cela fonctionne, juste après le super.layoutSubviews()
chargement des cellules. Cette solution équivaut à attendre l' willDisplay
événement du dernier chemin d'index. Cet événement est appelé lors de l'exécution layoutSubviews
de la vue tableau pour chaque cellule ajoutée.
• Un autre moyen consiste à être appelé lorsque l'application termine une passe de mise en page.
Comme décrit dans la documentation , vous pouvez utiliser une option du UIView.animate(withDuration:completion)
:
tableView.reloadData()
UIView.animate(withDuration: 0) {
// layout done
}
Cette solution fonctionne mais l'écran se rafraîchira une fois entre le moment où la mise en page est terminée et le moment où le bloc est appelé. Ceci est équivalent à la DispatchMain.async
solution mais spécifié.
• Sinon, je préférerais forcer la mise en page de la vue tableau
Il existe une méthode dédiée pour forcer toute vue à calculer immédiatement ses cadres de sous-vue layoutIfNeeded
:
tableView.reloadData()
table.layoutIfNeeded()
// layout done
Attention cependant, cela supprimera le chargement différé utilisé par le système. L'appel répété de ces méthodes peut créer des problèmes de performances. Assurez-vous qu'ils ne seront pas appelés avant que le cadre de la vue de table ne soit calculé, sinon la vue de table sera chargée à nouveau et vous ne serez pas averti.
Je pense qu'il n'y a pas de solution parfaite. Le sous-classement des classes peut conduire à des trubles. Une passe de mise en page commence par le haut et va vers le bas, il n'est donc pas facile d'être averti lorsque toute la mise en page est terminée. Et layoutIfNeeded()
pourrait créer des problèmes de performances, etc. Mais connaissant ces options, vous devriez être en mesure de penser à une alternative qui répondra à vos besoins.