Lors de l'insertion de plusieurs vues supplémentaires personnalisées dans une vue de collection avec des vues supplémentaires existantes, en utilisant une sous-classe de UICollectionViewFlowLayout, la collection semble créer des animations défectueuses ou ne gérer correctement les insertions.
L'insertion d'une vue supplémentaire se comporte comme prévu, mais l'insertion de deux vues supplémentaires en même temps entraîne un glitch visuel évident, et l'insertion de nombreuses vues supplémentaires en même temps (par exemple 4+) aggrave le problème. (iOS 10.2, iOS 9.3, Swift 3, Xcode 8.2.1)
Voici une démonstration:
Vous pouvez reproduire le problème en utilisant ce projet exemple. Dans cet exemple simplifié, il y a une vue supplémentaire pour chaque élément, et deux éléments (avec deux vues supplémentaires) sont insérés lors de chaque mise à jour par lots. Dans mon projet réel, j'ai moins de vues supplémentaires que d'éléments et j'utilise d'autres fonctionnalités de mise en page.
Ma meilleure supposition est que quelque chose cause la confusion de la vue de la collection entre les index ou les attributs de mise en page correspondant aux vues supplémentaires existantes/insérées. S'il s'avère que c'est un bogue dans l'une des classes d'Apple, je vous serais très reconnaissant pour votre solution la plus élégante.
Solutions tentées
J'ai essayé et vérifié chacune des solutions suivantes:
-
Mise en oeuvre de
indexPathsToInsertForSupplementaryView(ofKind:)
—pour autant que je puisse dire, c'est simple et mon implémentation renvoie les index paths corrects. Les vues sont toujours insérées. Pour les vues supplémentaires d'en-tête et de pied de page, UICollectionViewFlowLayout semble renvoyer un tableau trié d'index paths, mais trier le tableau n'a pas fait de différence pour moi. -
Fournir des attributs de mise en page initiaux et finaux—appeler
super
pour ces méthodes semble renvoyer les bons cadres, donc il n'est pas évident quels ajustements (le cas échéant) pourraient être apportés aux attributs de mise en page initiaux ou finaux pour résoudre le problème. Mais voir la troisième curiosité notée ci-dessous. -
Invalidation de la mise en page—cela semble ne faire aucune différence que la mise en page soit invalide manuellement en tout ou en partie avant, pendant ou après
performBatchUpdates()
, ou pas du tout. -
Index paths personnalisés—bien que les index paths pour les éléments supplémentaires n'aient pas besoin de correspondre aux index paths des éléments, autant que je puisse dire, et malgré la documentation contraire, UICollectionViewFlowLayout plantera (en demandant des attributs de mise en page pour des index paths inexistants) à moins que les éléments supplémentaires du même type ne soient numérotés séquentiellement à partir de 0. Je suppose que c'est ainsi que la vue de collection et/ou l'objet de mise en page est capable de calculer de nouveaux index paths lorsque des éléments sont insérés ou supprimés (c'est-à-dire en incrémentant ou en décrémentant la propriété
item
de l'index path). La construction d'index paths arbitraires n'est pas une option.
Curiosités remarquées lors du débogage
-
Les glitches visuels sont spécifiques aux vues supplémentaires et ne se produisent pas pour les éléments insérés, même lorsque les index paths et les cadres sont les mêmes pour les deux.
-
Le débogage de la hiérarchie des vues révèle que, bien que les cadres des vues supplémentaires insérées soient corrects, les cadres de certaines vues supplémentaires existantes ne sont pas corrects. Cela malgré le fait que les cadres renvoyés par l'objet de mise en page pour les vues existantes à ces index paths semblent être corrects.
-
Lors de l'insertion de plusieurs vues supplémentaires, les appels faits par la vue de la collection pour les attributs de mise en page initiaux et finaux semblent être déséquilibrés. En d'autres termes, les attributs de mise en page initiaux sont demandés plusieurs fois pour le même index path (et, naturellement, les mêmes attributs sont renvoyés à chaque fois), et il y a moins de demandes pour les attributs de mise en page finaux. De plus, pour certaines vues supplémentaires existantes, les attributs de mise en page initiaux et finaux ne sont jamais demandés du tout. Je trouve cela suspect. Cela me fait penser que la vue de la collection confond de quelque manière les vues supplémentaires et/ou les index paths avant et après la mise à jour.
-
Les adresses mémoire des instances d'IndexPath créées par mon code Swift sont très différentes des instances de NSIndexPath créées internalement par UICollectionView et UICollectionViewFlowLayout. Les premières sont toujours différentes (comme prévu), tandis que les secondes semblent être identiques entre les lancements (par exemple [0, 0], [0, 1] et [0, 2] sont toujours à
0xc000000000000016
,0xc000000000200016
et0xc000000000400016
). En Swift, IndexPath est converti en NSIndexPath, mais le premier est un type de valeur tandis que le second est un type de référence. NSIndexPath utilise également des pointeurs taggés. Il y a une possibilité lointaine que les deux aient été imparfaitement convertis et/ou que les classes de la vue de la collection reposent en interne sur le comportement de NSIndexPath d'une manière qui donne lieu à la confusion des index paths apparente ici. Je ne sais pas comment tester cela ou aller plus loin.
Questions similaires
Les questions suivantes peuvent être liées, bien que aucune des réponses ne fonctionne pour moi:
-
Comment insérer ou supprimer correctement les vues supplémentaires de UICollectionView
-
layoutAttributesForSupplementaryViewOfKind:atIndexPath: passe un index path incorrect
-
Les vues supplémentaires de UICollectionView ne s'animent pas correctement “en” ou “dehors”
-
Les vues décoratives et supplémentaires de UICollectionView ne peuvent pas être déplacées
Le problème peut également être lié à ce rapport de bug sur Open Radar. Cependant, le projet exemple accompagnant ce rapport est un peu trop compliqué pour être utile.
Support technique Apple
Après avoir publié cette question, j'ai soumis un incident de support technique à Apple. Le Support aux développeurs d'Apple a répondu ce qui suit:
Nos ingénieurs ont examiné votre demande et ont déterminé qu'il serait préférable de traiter cela comme un rapport de bug.
Veuillez soumettre un rapport de bug complet concernant ce problème en utilisant l'outil de signalement de bug disponible à l'adresse https://developer.apple.com/bug-reporting/.
...
Nous avons passé du temps à étudier la possibilité d'une solution de contournement et malheureusement nous sommes revenus bredouilles. Veuillez suivre avec votre rapport de bug. Si nous découvrons la possibilité d'une sorte de solution de contournement à l'avenir, nous vous contacterons. Désolé de ne pas avoir de meilleures nouvelles.
Si vous rencontrez ce problème, veuillez dupliquer le rdar://30510010.