Les animations sur iOS par la pratique : CAReplicatorLayer

le 30/05/2018 par Renaud Cousin
Tags: Software Engineering

Voir le lien github

Dans un précédent article sur les animations, j’expliquais les bases de CoreAnimation, les différentes manières de faire des animations, les pré-requis à connaître ainsi que les pièges à éviter. J’ai également parlé de tous les types prédéfinis de CALayer fournis par Apple, sans trop m’étendre.

Aujourd’hui, je compte vous amener de la théorie à la pratique avec des cas concrets par une série d’articles, chacun ayant pour sujet un type de CALayer.

Celui-ci va démystifier CAReplicatorLayer pour vous !

CAReplicatorLayer : Qu’est-ce que c’est ?

Selon la documentation Apple :

A layer that creates a specified number of copies of its sublayers (the source layer), each copy potentially having geometric, temporal, and color transformations applied to it.

Il s’agit donc d’un type de layer nous permettant de dupliquer un autre layer et ses animations, tout en nous laissant la possibilité d’en modifier l’aspect visuel.

Ok, mais concrètement, comment ce layer va-t-il m’aider dans mes animations ?

Lorsqu’Apple évoque le fait de dupliquer un layer, il ne s’agit pas seulement d’en copier l’aspect visuel, mais également toutes les animations qui y sont appliquées !

Regardons donc la documentation Apple d’un peu plus près :

Voir le lien github

Voici donc tous les contrôles que nous avons sur les objets dupliqués. Hormis instanceCount (qui comme son nom l’indique, défini le nombre de duplications), toutes ces propriétés représentent les différences que l’occurence n de mon objet aura par rapport à l'occurrence n-1.

Ainsi, si nous prenons le code suivant :

Voir le lien github

Nous créons le CALayer tile puis le CAReplicatorLayer et lui ajoutons tile en subLayer pour l’utiliser en “source layer”. C’est ensuite que tout l’intérêt du CAReplicatorLayer commence !

Nous indiquons que :

  • nous souhaitons 6 instances de tile (l’original + 5 copies)

  • chaque instance sera translatée en x de la largeur de tile

  • chaque instance verra son opacité diminuée de 15% par rapport à la précédente

Puis nous ajoutons le replicator à la vue.

Et voilà le résultat :Si nous remplaçons instanceAlphaOffset par instanceRedOffset, nous obtenons ceci :

Attention !

Chaque propriété instanceXXXOffset fonctionne comme un pourcentage, elle prend une valeur comprise entre 0 et 1, en positif ou négatif. Je m’explique !

Prenons le cas de instanceAlphaOffset. L’opacité est bien évidemment comprise entre 0 (transparent) et 1 (opaque). Lorsque vous donnez une valeur à cette propriété, vous indiquez l’opération à effectuer à partir de l’instance n-1 pour obtenir l’instance n. Ainsi, si l’instance n-1 a une opacité de 1 et que vous souhaitez diminuer l’opacité des instances suivantes, vous allez spécifier une valeur négative. Si vous spécifiez une valeur positive, l’opacité des instances suivantes sera supérieure à 1, donc 1 ! À l’inverse évidemment, si l’opacité de départ est inférieure à 1 et que vous souhaitez des instances avec une opacité de plus en plus opaque, vous passerez une valeur positive.

Le fonctionnement est absolument le même pour les offsets appliqués aux composantes de couleur (instanceRedOffset, ...), à la différence que ces composantes sont comprises entre 0 et 255 (0: pas de rouge, 255: composante rouge au maximum). Cependant, vous appliquerez une valeur comprise entre 0 et 1 comme pour l’opacité.

Pour bien comprendre : Si vous avez un source layer de couleur rouge (red:255, green:0, blue:0, alpha:1)et que vous appliquez une valeur instanceRedOffset de -0.5 (-50%) :

Voir le lien github

La première instance sera rouge (red:255, green:0, blue:0, alpha:1), la seconde sera rouge très foncé (red:127, green:0, blue:0, alpha:1) —à mi chemin entre rouge et noir— , et la troisième ainsi que toutes les suivantes seront noires (red:0, green:0, blue:0, alpha:1)

Enfin, sachez que toutes ces propriétés peuvent être combinées !

Voir le lien github

Ok, mais ne perdons pas de vu notre objectif : l’animation !

Nous venons de voir que nous avons un contrôle sur l’aspect des duplicatas ainsi que leur position, mais ce qui nous intéresse maintenant, c’est d’animer le tout ! Et surtout, dans quel(s) cas ça pourrait nous servir ?!

Prenons le cas d’une animation simple : un trait gris dont on anime l’opacité de 1 à 0, en boucle infinie. Nous la construisons comme suit :

Voir le lien github

Maintenant, nous allons encapsuler ce layer dans un autre layer —qui servira de conteneur— comme ceci :Le but de cette démarche est désormais d’utiliser ce layer conteneur comme source de notre CAReplicatorLayer et d’appliquer un rotation entre chaque instance :

Vous commencez à voir où je veux en venir ??

Pour la suite, nous allons créer le replicatorLayer, lui passer un nombre d’instances, un délai et une rotation de 360°/nombre d’instances sur l’axe Z. Enfin, nous ajoutons le conteneur au replicatorLayer.

Voir le lien github

Vous venez de recréer le UIActivityIndicatorView de UIKit !!

Points d’attention :

Pour que l’animation fonctionne, nous avons déporté l’animation de stroke sur le conteneur car sinon, l’animation ne sera pas répliquée. Enfin, pour que l’animation boucle correctement, la durée de l’animation initiale est calculée par rapport au nombre d’instances et du délai entre chacunes.

Pour aller plus loin :

Maintenant que vous avez compris le principe, à vous d’expérimenter pour explorer les possibilités que vous offre le CAReplicatorLayer !

Mais, sachez que le replicatorLayer ne reste qu’un CALayer, donc vous pouvez très bien imaginer ajouter un replicatorLayer à un autre !

En voici le code :

Voir le lien github

Maintenant, c’est à vous de jouer !