Articles

Exécution D’Animations iOS Sur Des Vues Avec UIKit Et UIView

  • 14 min de lecture
  • Animation, iOS, interface utilisateur, Mobile
  • Enregistré pour une lecture hors ligne
  • Partager sur Twitter, LinkedIn

div>

Cet article vise à être une amorce sur les animations iOS couvrant de manière exhaustive différentes façons de le faire. Nous commençons par comprendre les bases des animations, passons aux Frameworks de base en construisant un seul exemple en utilisant les différentes méthodes proposées et enfin en cherchant des moyens d’ajuster les performances.

Je suis développeur iOS depuis plus d’une décennie maintenant et j’ai rarement vu des articles qui consolident toutes les façons possibles d’effectuer des animations dans iOS. Cet article vise à être une introduction sur les animations iOS dans le but de couvrir de manière exhaustive les différentes façons de faire de même.

Compte tenu de l’ampleur du sujet, nous couvririons chaque partie de manière succincte à un niveau assez élevé. L’objectif est d’éduquer le lecteur avec un ensemble de choix pour ajouter des animations à son application iOS.

Avant de commencer avec des sujets liés à iOS, jetons un bref coup d’œil à la vitesse d’animation.

Animation À 60 images/s

Généralement dans les vidéos, chaque image est représentée par une image et la fréquence d’images détermine le nombre d’images retournées dans la séquence. Ceci est appelé « images par seconde » ou FPS.

FPS détermine le nombre d’images fixes retournées en une seconde, ce qui signifie littéralement que plus le nombre d’images / images augmente, plus de détails / informations sont affichés dans la vidéo. Cela vaut également pour les animations.

Le FPS est généralement utilisé pour déterminer la qualité des animations. Il existe une opinion populaire selon laquelle toute bonne animation devrait fonctionner à 60 images par seconde ou plus — tout ce qui est inférieur à 60 images par seconde se sentirait un peu décalé.

Voulez-vous voir la différence entre 30FPS et 60FPS? Regarde ça !

Avez-vous remarqué la différence? Les yeux humains peuvent certainement sentir la gigue à des fps inférieurs. Par conséquent, c’est toujours une bonne pratique de s’assurer que toute animation que vous créez adhère à la règle de base consistant à fonctionner à 60 images par seconde ou plus. Cela le rend plus réaliste et vivant.

Après avoir examiné les FPS, examinons maintenant les différents frameworks iOS de base qui nous fournissent un moyen d’effectuer des animations.

Cadres de base

Dans cette section, nous aborderons les cadres du SDK iOS qui peuvent être utilisés pour créer des animations de vue. Nous ferons une promenade rapide à travers chacun d’eux, expliquant leur ensemble de fonctionnalités avec un exemple pertinent.

Animations UIKit/UIView

UIView est la classe de base de toute vue qui affiche du contenu dans les applications iOS.

UIKit, le framework qui nous donne UIView, nous fournit déjà quelques fonctions d’animation de base qui permettent aux développeurs d’obtenir plus en faisant moins.

L’API, UIView.animate, est le moyen le plus simple d’animer des vues car les propriétés de n’importe quelle vue peuvent être facilement animées en fournissant les valeurs de propriété dans la syntaxe basée sur les blocs.

Dans les animations UIKit, il est recommandé de ne modifier que les propriétés animables d’UIVIew, sinon il y aura des répercussions lorsque les animations risquent de faire en sorte que la vue se retrouve dans un état inattendu.

animation (withDuration:animations:completion)

Cette méthode prend en compte la durée de l’animation, un ensemble de modifications de propriétés animables de la vue qui doivent être animées. Le bloc de complétion donne un rappel lorsque la vue est terminée avec l’exécution de l’animation.

Presque tout type d’animation comme le déplacement, la mise à l’échelle, la rotation, la décoloration, etc. sur une vue peut être réalisée avec cette API unique.

Maintenant, considérez que vous souhaitez animer un changement de taille de bouton ou que vous souhaitez qu’une vue particulière zoome sur l’écran. Voici comment nous pouvons le faire en utilisant l’API UIView.animate:

let newButtonWidth: CGFloat = 60UIView.animate(withDuration: 2.0) { //1 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) //2 self.button.center = self.view.center //3}

Voici ce que nous faisons ici:

  1. Nous appelons la méthode UIView.animate avec une valeur de durée qui lui est transmise qui représente la durée pendant laquelle l’animation, décrite à l’intérieur du bloc, doit s’exécuter.
  2. Nous définissons le nouveau cadre du bouton qui doit représenter l’état final de l’animation.
  3. Nous définissons le bouton center avec le centre de sa vue d’ensemble afin qu’il reste au centre de l’écran.

Le bloc de code d’animation ci-dessus devrait déclencher l’animation de la trame du bouton en passant de la trame actuelle:

Width = 0, Height = 0

À la trame finale:

Width = Height = newButtonWidth

Et voici à quoi ressemblerait l’animation:

animateWithDuration

Cette méthode est comme une extension de la méthode animate où vous pouvez faire tout ce que vous pouvez effectuer dans l’API précédente avec certains comportements physiques ajoutés aux animations de vue.

Par exemple, si vous souhaitez obtenir des effets d’amortissement de ressort dans l’animation que nous avons faite ci-dessus, voici à quoi ressemblerait le code:

let newButtonWidth: CGFloat = 60UIView.animate(withDuration: 1.0, //1 delay: 0.0, //2 usingSpringWithDamping: 0.3, //3 initialSpringVelocity: 1, //4 options: UIView.AnimationOptions.curveEaseInOut, //5 animations: ({ //6 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center}), completion: nil)

Voici l’ensemble de paramètres que nous utilisons:

  1. duration
    Représente la durée de l’animation déterminant la durée d’exécution du bloc de code.
  2. delay
    Représente le délai initial que nous voulons avoir avant le début de l’animation.
  3. SpringWithDamping
    Représente la valeur de l’effet élastique que nous voulons que la vue se comporte. La valeur doit être comprise entre 0 et 1. Plus la valeur est basse, plus l’oscillation du ressort est élevée.
  4. velocity
    Représente la vitesse à laquelle l’animation doit démarrer.
  5. options
    Type de courbe d’animation que vous souhaitez appliquer à votre animation de vue.
  6. Enfin, le bloc de code où nous définissons le cadre du bouton qui doit être animé. C’est la même chose que l’animation précédente.

Et voici à quoi ressemblerait l’animation avec la configuration d’animation ci-dessus:

UIViewPropertyAnimator

Pour un peu plus de contrôle sur les animations, UIViewPropertyAnimator est pratique là où il est nous fournit un moyen de mettre en pause et de reprendre les animations. Vous pouvez avoir un timing personnalisé et faire en sorte que votre animation soit interactive et interruptible. Ceci est très utile lors de l’exécution d’animations qui peuvent également interagir avec les actions de l’utilisateur.

Le geste classique « Glisser pour déverrouiller » et l’animation de rejet /expansion de la vue du lecteur (dans l’application Musique) sont des exemples d’animations interactives et interruptibles. Vous pouvez commencer à déplacer une vue avec votre doigt, puis la relâcher et la vue reviendra à sa position d’origine. Alternativement, vous pouvez capturer la vue pendant l’animation et continuer à la faire glisser avec votre doigt.

Voici un exemple simple de la façon dont nous pourrions réaliser l’animation en utilisant UIViewPropertyAnimator:

let newButtonWidth: CGFloat = 60let animator = UIViewPropertyAnimator(duration:0.3, curve: .linear) { //1 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center}animator.startAnimation() //2

Voici ce que nous faisons:

  1. On appelle l’API UIViewProperty en passant la durée et la courbe d’animation.
  2. Contrairement aux deux UIView ci-dessus.API animate, l’animation ne démarrera que si vous le spécifiez vous-même, c’est-à-dire que vous contrôlez entièrement le processus / flux d’animation complet.

Maintenant, disons que vous voulez encore plus de contrôle sur les animations. Par exemple, vous souhaitez concevoir et contrôler chaque image de l’animation. Il existe une autre API pour cela, animateKeyframes. Mais avant de nous y plonger, regardons rapidement ce qu’est un cadre, dans une animation.

Qu’Est-Ce Qu’Un frame ?

Une collection des changements/transitions de trame de la vue, de l’état de départ à l’état final, est définie comme animation et chaque position de la vue pendant l’animation est appelée comme un frame.

animateKeyframes

Cette API fournit un moyen de concevoir l’animation de telle sorte que vous puissiez définir plusieurs animations avec des timings et des transitions différents. Postez ceci, l’API intègre simplement toutes les animations dans une expérience transparente.

Disons que nous voulons déplacer notre bouton sur l’écran de manière aléatoire. Voyons comment nous pouvons utiliser l’API d’animation d’images clés pour le faire.

UIView.animateKeyframes(withDuration: 5, //1 delay: 0, //2 options: .calculationModeLinear, //3 animations: { //4 UIView.addKeyframe( //5 withRelativeStartTime: 0.25, //6 relativeDuration: 0.25) { //7 self.button.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.maxY) //8 } UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.25) { self.button.center = CGPoint(x: self.view.bounds.width, y: start.y) } UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) { self.button.center = start }})

Voici la ventilation:

  1. duration
    Appelez l’API en passant la durée de l’animation.
  2. delay
    Durée du délai initial de l’animation.
  3. options
    Le type de courbe d’animation que vous souhaitez appliquer à votre animation de vue.
  4. animations
    Bloc qui prend toutes les animations d’images clés conçues par le développeur / utilisateur.
  5. addKeyFrame
    Appelez l’API pour concevoir chaque animation. Dans notre cas, nous avons défini chaque mouvement du bouton. Nous pouvons avoir autant d’animations que nécessaire, ajoutées au bloc.
  6. relativeStartTime
    Définit l’heure de début de l’animation dans la collection du bloc d’animation.
  7. relativeDuration
    Définit la durée globale de cette animation spécifique.
  8. center
    Dans notre cas, nous modifions simplement la propriété centrale du bouton pour déplacer le bouton sur l’écran.

Et voici à quoi ressemblent les animations finales:

CoreAnimation

Toute animation basée sur UIKit est traduite en animations de base. Ainsi, le framework d’animation de base agit comme une couche de support ou une colonne vertébrale pour toute animation UIKit. Par conséquent, toutes les API d’animation UIKit ne sont que des couches encapsulées des API d’animation de base de manière facilement consommable ou pratique.

Les API d’animation UIKit ne fournissent pas beaucoup de contrôle sur les animations effectuées sur une vue car elles sont principalement utilisées pour les propriétés animables de la vue. Par conséquent, dans de tels cas, où vous avez l’intention de contrôler chaque image de l’animation, il est préférable d’utiliser directement les API d’animation de base sous-jacentes. Alternativement, les animations UIView et les animations de base peuvent également être utilisées conjointement.

UIView + Core Animation

Voyons comment nous pouvons recréer la même animation de changement de bouton avec la spécification de la courbe de synchronisation à l’aide des API UIView et Core Animation.

Nous pouvons utiliser les fonctions de synchronisation de CATransaction, qui vous permettent de spécifier et de contrôler la courbe d’animation.

Regardons un exemple d’animation de changement de taille de bouton avec son rayon de coin utilisant la fonction de synchronisation de CATransaction et une combinaison d’animations UIView:

let oldValue = button.frame.width/2let newButtonWidth: CGFloat = 60/* Do Animations */CATransaction.begin() //1CATransaction.setAnimationDuration(2.0) //2CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)) //3// View animations //4UIView.animate(withDuration: 1.0) { self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center}// Layer animationslet cornerAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.cornerRadius)) //5cornerAnimation.fromValue = oldValue //6cornerAnimation.toValue = newButtonWidth/2 //7button.layer.cornerRadius = newButtonWidth/2 //8button.layer.add(cornerAnimation, forKey: #keyPath(CALayer.cornerRadius)) //9CATransaction.commit() //10

Voici la répartition:

  1. begin
    Représente le début du bloc de code d’animation.
  2. duration
    Durée globale de l’animation.
  3. curve
    Représente la courbe de synchronisation qui doit être appliquée à l’animation.
  4. UIView.animate
    Notre première animation pour changer le cadre du bouton.
  5. CABasicAnimation
    Nous créons l’objet CABasicAnimation en référençant le cornerRadius du bouton comme chemin de clé car c’est ce que nous voulons animer. De même, si vous souhaitez avoir un contrôle de niveau granulaire sur les animations d’images clés, vous pouvez utiliser la classe CAKeyframeAnimation.
  6. fromValue
    Représente la valeur de départ de l’animation, c’est-à-dire la valeur initiale cornerRadius du bouton à partir duquel l’animation doit démarrer.
  7. toValue
    Représente la valeur finale de l’animation, c’est-à-dire la valeur finale cornerRadius du bouton où l’animation doit se terminer.
  8. cornerRadius
    Nous devons définir la propriété cornerRadius du bouton avec la valeur finale de l’animation sinon la valeur cornerRadius du bouton sera automatiquement rétablie à sa valeur initiale une fois l’animation terminée.
  9. addAnimation
    Nous attachons l’objet d’animation qui contient la configuration de l’ensemble du processus d’animation à la couche en représentant le chemin de clé pour lequel l’animation doit être effectuée.
  10. commit
    Représente la fin du bloc de code d’animation et démarre l’animation.

Voici à quoi ressemblerait l’animation finale:

Ce blog est une excellente lecture pour aider à créer des animations plus avancées car il vous guide parfaitement à travers la plupart des API du framework d’animation principal avec des instructions vous guidant à travers chaque étape du chemin.

UIKitDynamics

UIKit Dynamics est le moteur physique de UIKit qui vous permet d’ajouter des comportements physiques tels que collision, gravité, poussée, accrochage, etc. aux contrôles UIKit.

UIKitDynamicAnimator

C’est la classe admin du framework UIKit Dynamics qui régule toutes les animations déclenchées par un contrôle d’interface utilisateur donné.

UIKitDynamicBehavior

Il vous permet d’ajouter n’importe quel comportement physique à un animateur qui lui permet ensuite de s’exécuter sur la vue qui lui est attachée.

Différents types de comportements pour UIKitDynamics incluent:

  • UIAttachmentBehavior
  • UICollisionBehavior
  • UIFieldBehavior
  • UIGravityBehavior
  • UIPushBehavior
  • UISnapBehavior

L’architecture de UIKitDynamics ressemble à ceci. Notez que les éléments 1 à 5 peuvent être remplacés par une seule vue.

Appliquons un comportement physique à notre bouton. Nous verrons comment appliquer la gravité au bouton pour qu’il nous donne l’impression de traiter un objet réel.

var dynamicAnimator : UIDynamicAnimator!var gravityBehavior : UIGravityBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: ) //2dynamicAnimator.addBehavior(gravityBehavior) //3

Voici la ventilation:

  1. UIKitDynamicAnimator
    Nous avons créé un objet UIKitDynamicAnimator qui agit comme un orchestrateur pour effectuer des animations. Nous avons également passé la vue d’ensemble de notre bouton comme vue de référence.
  2. UIGravityBehavior
    Nous avons créé un objet UIGravityBehavior et passons notre bouton dans les éléments du tableau sur lesquels ce comportement est injecté.
  3. addBehavior
    Nous avons ajouté l’objet gravity à l’animateur.
    Cela devrait créer une animation comme indiqué ci-dessous:

    Remarquez comment le bouton tombe du centre (sa position d’origine) de l’écran vers le bas et au-delà.

    Nous devrions dire à l’animateur de considérer le bas de l’écran comme étant le sol. C’est là que UICollisionBehavior entre en image.

    var dynamicAnimator : UIDynamicAnimator!var gravityBehavior : UIGravityBehavior!var collisionBehavior : UICollisionBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: ) //2dynamicAnimator.addBehavior(gravityBehavior) //3collisionBehavior = UICollisionBehavior(items: ) //4collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5dynamicAnimator.addBehavior(collisionBehavior) //6
  4. UICollisionBehavior
    Nous avons créé un objet UICollisionBehavior et passé le long du bouton pour que le comportement soit ajouté à l’élément.
  5. translatesReferenceBoundsIntoBoundary
    L’activation de cette propriété indique à l’animateur de prendre la limite des vues de référence comme fin, qui est le bas de l’écran dans notre cas.
  6. addBehavior
    Nous avons ajouté un comportement de collision à l’animateur ici.
    Maintenant, notre bouton devrait toucher le sol et rester immobile comme indiqué ci-dessous:

    C’est assez soigné, n’est-ce pas?
    Maintenant, essayons d’ajouter un effet de rebond pour que notre objet se sente plus réel. Pour ce faire, nous utiliserons la classe UIDynamicItemBehavior.

    var dynamicAnimator : UIDynamicAnimator!var gravityBehavior : UIGravityBehavior!var collisionBehavior : UICollisionBehavior!var bouncingBehavior : UIDynamicItemBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: ) //2dynamicAnimator.addBehavior(gravityBehavior) //3collisionBehavior = UICollisionBehavior(items: ) //4collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5dynamicAnimator.addBehavior(collisionBehavior) //6//Adding the bounce effectbouncingBehavior = UIDynamicItemBehavior(items: ) //7bouncingBehavior.elasticity = 0.75 //8dynamicAnimator.addBehavior(bouncingBehavior) //9
  7. UIDynamicItemBehavior
    Nous avons créé un objet UIDynamicItemBehavior et passons le bouton pour que le comportement soit ajouté à l’élément.
  8. elasticity
    La valeur doit être comprise entre 0 et 1, elle représente l’élasticité, c’est-à-dire le nombre de fois où l’objet doit rebondir sur et hors du sol lorsqu’il est touché. C’est là que la magie se produit — en modifiant cette propriété, vous pouvez différencier différents types d’objets tels que des balles, des bouteilles, des objets durs, etc.
  9. addBehavior
    Nous avons ajouté un comportement de collision à l’animateur ici.

Maintenant, notre bouton devrait rebondir lorsqu’il touche le sol comme indiqué ci-dessous:

Ce dépôt est très utile et montre tous les comportements UIKitDynamics en action. Il fournit également du code source pour jouer avec chaque comportement. Cela, à mon avis, devrait servir de liste exhaustive de façons d’effectuer des animations iOS sur les vues!

Dans la section suivante, nous examinerons brièvement les outils qui nous aideront à mesurer les performances des animations. Je vous recommande également de rechercher des moyens d’optimiser votre build Xcode car cela vous permettra d’économiser énormément de temps de développement.

Réglage des performances

Dans cette section, nous examinerons les moyens de mesurer et d’ajuster les performances des animations iOS. En tant que développeur iOS, vous avez peut-être déjà utilisé des instruments Xcode tels que des fuites de mémoire et des allocations pour mesurer les performances de l’ensemble de l’application. De même, il existe des instruments qui peuvent être utilisés pour mesurer les performances des animations.

Core AnimationInstrument

Essayez l’instrument Core Animation et vous devriez pouvoir voir le FPS fourni par l’écran de votre application. C’est un excellent moyen de mesurer les performances / la vitesse de toute animation rendue dans votre application iOS.

Dessin

Le FPS est considérablement réduit dans l’application qui affiche un contenu lourd comme des images avec des effets comme des ombres. Dans de tels cas, au lieu d’affecter l’Image directement à la propriété image de UIImageView, essayez de dessiner l’image séparément dans un contexte à l’aide des API Core Graphics. Cela réduit excessivement le temps d’affichage de l’image en effectuant la logique de décompression de l’image de manière asynchrone lorsqu’elle est effectuée dans un thread séparé au lieu du thread principal.

Rastérisation

La rastérisation est un processus utilisé pour mettre en cache des informations de couche complexes afin que ces vues ne soient pas redessinées chaque fois qu’elles sont rendues. Le redessinage des vues est la principale cause de la réduction du FPS et, par conséquent, il est préférable d’appliquer la rastérisation sur les vues qui vont être réutilisées plusieurs fois.

En conclusion

Pour conclure, j’ai également résumé une liste de ressources utiles pour les animations iOS. Vous trouverez peut-être cela très pratique lorsque vous travaillez sur des animations iOS. De plus, vous pouvez également trouver cet ensemble d’outils de conception utile comme étape (de conception) avant de vous plonger dans les animations.