Animations personnalisées dans Xamarin.Forms
La classe Animation est le bloc de construction de toutes les Xamarin.Forms animations, les méthodes d’extension de la classe ViewExtensions créant un ou plusieurs objets Animation. Cet article explique comment utiliser la classe Animation pour créer et annuler des animations, synchroniser plusieurs animations et créer des animations personnalisées qui animent des propriétés qui ne sont pas animées par les méthodes d’animation existantes.
Un certain nombre de paramètres doivent être spécifiés lors de la création d’un Animation
objet, notamment les valeurs de début et de fin de la propriété animée, ainsi qu’un rappel qui modifie la valeur de la propriété. Un Animation
objet peut également gérer une collection d’animations enfants qui peuvent être exécutées et synchronisées. Pour plus d’informations, consultez Animations enfants.
L’exécution d’une animation créée avec la Animation
classe , qui peut inclure ou non des animations enfants, est obtenue en appelant la Commit
méthode . Cette méthode spécifie la durée de l’animation et, entre autres éléments, un rappel qui contrôle la répétition de l’animation.
En outre, la Animation
classe a une IsEnabled
propriété qui peut être examinée pour déterminer si les animations ont été désactivées par le système d’exploitation, par exemple lorsque le mode d’économie d’énergie est activé.
Créer une animation
Lors de la création d’un Animation
objet, un minimum de trois paramètres est généralement requis, comme illustré dans l’exemple de code suivant :
var animation = new Animation (v => image.Scale = v, 1, 2);
Ce code définit une animation de la Scale
propriété d’un Image
instance d’une valeur de 1 à une valeur de 2. La valeur animée, qui est dérivée de Xamarin.Forms, est passée au rappel spécifié comme premier argument, où elle est utilisée pour modifier la valeur de la Scale
propriété .
L’animation est démarrée avec un appel à la Commit
méthode , comme illustré dans l’exemple de code suivant :
animation.Commit (this, "SimpleAnimation", 16, 2000, Easing.Linear, (v, c) => image.Scale = 1, () => true);
Notez que la Commit
méthode ne retourne pas d’objet Task
. Au lieu de cela, les notifications sont fournies par le biais de méthodes de rappel.
Les arguments suivants sont spécifiés dans la Commit
méthode :
- Le premier argument (propriétaire) identifie le propriétaire de l’animation. Il peut s’agir de l’élément visuel sur lequel l’animation est appliquée, ou d’un autre élément visuel, tel que la page.
- Le deuxième argument (nom) identifie l’animation avec un nom. Le nom est combiné avec le propriétaire pour identifier l’animation de manière unique. Cette identification unique peut ensuite être utilisée pour déterminer si l’animation est en cours d’exécution (
AnimationIsRunning
), ou pour l’annuler (AbortAnimation
). - Le troisième argument (taux) indique le nombre de millisecondes entre chaque appel à la méthode de rappel définie dans le
Animation
constructeur. - Le quatrième argument (longueur) indique la durée de l’animation, en millisecondes.
- Le cinquième argument (easing) définit la fonction d’accélération à utiliser dans l’animation. Vous pouvez également spécifier la fonction d’accélération en tant qu’argument du
Animation
constructeur. Pour plus d’informations sur l’accélération des fonctions, consultez Fonctions d’accélération. - Le sixième argument (terminé) est un rappel qui sera exécuté une fois l’animation terminée. Ce rappel prend deux arguments, le premier argument indiquant une valeur finale et le second argument étant un
bool
qui est défini surtrue
si l’animation a été annulée. Vous pouvez également spécifier le rappel terminé en tant qu’argument duAnimation
constructeur. Toutefois, avec une seule animation, si des rappels terminés sont spécifiés à la fois dans leAnimation
constructeur et dans laCommit
méthode, seul le rappel spécifié dans laCommit
méthode est exécuté. - Le septième argument (répéter) est un rappel qui permet de répéter l’animation. Elle est appelée à la fin de l’animation, et le retour
true
indique que l’animation doit être répétée.
L’effet global est de créer une animation qui augmente la Scale
propriété d’un Image
de 1 à 2, sur 2 secondes (2 000 millisecondes), à l’aide de la Linear
fonction d’accélération. Chaque fois que l’animation se termine, sa Scale
propriété est réinitialisée à 1 et l’animation se répète.
Notes
Les animations simultanées, qui s’exécutent indépendamment les unes des autres, peuvent être construites en créant un Animation
objet pour chaque animation, puis en appelant la Commit
méthode sur chaque animation.
Animations enfants
La Animation
classe prend également en charge les animations enfants, ce qui implique la création d’un Animation
objet auquel d’autres Animation
objets sont ajoutés. Cela permet d’exécuter et de synchroniser une série d’animations. L’exemple de code suivant illustre la création et l’exécution d’animations enfants :
var parentAnimation = new Animation ();
var scaleUpAnimation = new Animation (v => image.Scale = v, 1, 2, Easing.SpringIn);
var rotateAnimation = new Animation (v => image.Rotation = v, 0, 360);
var scaleDownAnimation = new Animation (v => image.Scale = v, 2, 1, Easing.SpringOut);
parentAnimation.Add (0, 0.5, scaleUpAnimation);
parentAnimation.Add (0, 1, rotateAnimation);
parentAnimation.Add (0.5, 1, scaleDownAnimation);
parentAnimation.Commit (this, "ChildAnimations", 16, 4000, null, (v, c) => SetIsEnabledButtonState (true, false));
Vous pouvez également écrire l’exemple de code de manière plus concise, comme illustré dans l’exemple de code suivant :
new Animation {
{ 0, 0.5, new Animation (v => image.Scale = v, 1, 2) },
{ 0, 1, new Animation (v => image.Rotation = v, 0, 360) },
{ 0.5, 1, new Animation (v => image.Scale = v, 2, 1) }
}.Commit (this, "ChildAnimations", 16, 4000, null, (v, c) => SetIsEnabledButtonState (true, false));
Dans les deux exemples de code, un objet parent Animation
est créé, auquel des objets supplémentaires Animation
sont ensuite ajoutés. Les deux premiers arguments de la Add
méthode spécifient quand commencer et terminer l’animation enfant. Les valeurs d’argument doivent être comprises entre 0 et 1 et représentent la période relative dans l’animation parente pendant laquelle l’animation enfant spécifiée sera active. Par conséquent, dans cet exemple, le scaleUpAnimation
sera actif pour la première moitié de l’animation, le scaleDownAnimation
sera actif pour la deuxième moitié de l’animation et le rotateAnimation
sera actif pendant toute la durée.
L’effet global est que l’animation se produit sur 4 secondes (4 000 millisecondes). le scaleUpAnimation
anime la Scale
propriété de 1 à 2, sur 2 secondes. Le scaleDownAnimation
anime ensuite la Scale
propriété de 2 à 1, sur 2 secondes. Pendant que les deux animations de mise à l’échelle se produisent, le rotateAnimation
anime la Rotation
propriété de 0 à 360, sur 4 secondes. Notez que les animations de mise à l’échelle utilisent également des fonctions d’accélération. La SpringIn
fonction d’accélération entraîne la Image
réduction initiale du avant d’être agrandie, et la SpringOut
fonction d’accélération fait en sorte que la Image
taille réelle de l’objet devienne inférieure à sa taille réelle vers la fin de l’animation complète.
Il existe un certain nombre de différences entre un Animation
objet qui utilise des animations enfants et un autre qui ne le fait pas :
- Lors de l’utilisation d’animations enfants, le rappel terminé sur une animation enfant indique quand l’enfant est terminé, et le rappel terminé passé à la
Commit
méthode indique quand l’animation entière est terminée. - Lors de l’utilisation d’animations enfants, le retour
true
à partir du rappel répété sur laCommit
méthode n’entraîne pas la répétition de l’animation, mais l’animation continuera à s’exécuter sans nouvelles valeurs. - Lorsque vous incluez une fonction d’accélération dans la
Commit
méthode et que la fonction d’accélération retourne une valeur supérieure à 1, l’animation est terminée. Si la fonction d’accélération retourne une valeur inférieure à 0, la valeur est limitée à 0. Pour utiliser une fonction d’accélération qui retourne une valeur inférieure à 0 ou supérieure à 1, elle doit être spécifiée dans l’une des animations enfants, plutôt que dans laCommit
méthode .
La Animation
classe inclut également des WithConcurrent
méthodes qui peuvent être utilisées pour ajouter des animations enfants à un objet parent Animation
. Toutefois, leurs valeurs d’argument de début et de fin ne sont pas limitées à 0 à 1, mais seule la partie de l’animation enfant qui correspond à une plage comprise entre 0 et 1 sera active. Par exemple, si un WithConcurrent
appel de méthode définit une animation enfant qui cible une Scale
propriété comprise entre 1 et 6, mais avec des valeurs de début et de fin de -2 et 3, la valeur de début de -2 correspond à une Scale
valeur de 1 et la valeur de fin de 3 correspond à une Scale
valeur de 6. Étant donné que les valeurs situées en dehors de la plage de 0 et 1 ne jouent aucun rôle dans une animation, la Scale
propriété ne sera animée que de 3 à 6.
Annuler une animation
Une application peut annuler une animation avec un appel à la méthode d’extension AbortAnimation
, comme illustré dans l’exemple de code suivant :
this.AbortAnimation ("SimpleAnimation");
Notez que les animations sont identifiées de manière unique par une combinaison du propriétaire de l’animation et du nom de l’animation. Par conséquent, le propriétaire et le nom spécifiés lors de l’exécution de l’animation doivent être spécifiés pour annuler l’animation. Par conséquent, l’exemple de code annule immédiatement l’animation nommée SimpleAnimation
qui appartient à la page.
Créer une animation personnalisée
Les exemples présentés ici jusqu’à présent ont montré des animations qui pouvaient également être obtenues avec les méthodes de la ViewExtensions
classe . Toutefois, l’avantage de la Animation
classe est qu’elle a accès à la méthode de rappel, qui est exécutée lorsque la valeur animée change. Cela permet au rappel d’implémenter l’animation souhaitée. Par exemple, l’exemple de code suivant anime la BackgroundColor
propriété d’une page en lui affectant des Color
valeurs créées par la Color.FromHsla
méthode, avec des valeurs de teinte comprises entre 0 et 1 :
new Animation (callback: v => BackgroundColor = Color.FromHsla (v, 1, 0.5),
start: 0,
end: 1).Commit (this, "Animation", 16, 4000, Easing.Linear, (v, c) => BackgroundColor = Color.Default);
L’animation obtenue donne l’apparence d’avancer l’arrière-plan de la page à travers les couleurs de l’arc-en-ciel.
Pour obtenir d’autres exemples de création d’animations complexes, notamment une animation de courbe de Bézier, consultez le chapitre 22 de Création d’applications mobiles avec Xamarin.Forms.
Créer une méthode d’extension d’animation personnalisée
Les méthodes d’extension de la ViewExtensions
classe animent une propriété de sa valeur actuelle vers une valeur spécifiée. Cela rend difficile la création, par exemple, d’une méthode d’animation ColorTo
qui peut être utilisée pour animer une couleur d’une valeur à une autre, car :
- La seule
Color
propriété définie par laVisualElement
classe estBackgroundColor
, qui n’est pas toujours la propriété souhaitéeColor
à animer. - Souvent, la valeur actuelle d’une
Color
propriété estColor.Default
, qui n’est pas une couleur réelle et qui ne peut pas être utilisée dans les calculs d’interpolation.
La solution à ce problème consiste à ne pas que la ColorTo
méthode cible une propriété particulière Color
. Au lieu de cela, il peut être écrit avec une méthode de rappel qui transmet la valeur interpolée Color
à l’appelant. En outre, la méthode accepte les arguments de début et de fin Color
.
La ColorTo
méthode peut être implémentée en tant que méthode d’extension qui utilise la Animate
méthode dans la AnimationExtensions
classe pour fournir ses fonctionnalités. En effet, la Animate
méthode peut être utilisée pour cibler des propriétés qui ne sont pas de type double
, comme illustré dans l’exemple de code suivant :
public static class ViewExtensions
{
public static Task<bool> ColorTo(this VisualElement self, Color fromColor, Color toColor, Action<Color> callback, uint length = 250, Easing easing = null)
{
Func<double, Color> transform = (t) =>
Color.FromRgba(fromColor.R + t * (toColor.R - fromColor.R),
fromColor.G + t * (toColor.G - fromColor.G),
fromColor.B + t * (toColor.B - fromColor.B),
fromColor.A + t * (toColor.A - fromColor.A));
return ColorAnimation(self, "ColorTo", transform, callback, length, easing);
}
public static void CancelAnimation(this VisualElement self)
{
self.AbortAnimation("ColorTo");
}
static Task<bool> ColorAnimation(VisualElement element, string name, Func<double, Color> transform, Action<Color> callback, uint length, Easing easing)
{
easing = easing ?? Easing.Linear;
var taskCompletionSource = new TaskCompletionSource<bool>();
element.Animate<Color>(name, transform, callback, 16, length, easing, (v, c) => taskCompletionSource.SetResult(c));
return taskCompletionSource.Task;
}
}
La Animate
méthode nécessite un argument de transformation , qui est une méthode de rappel. L’entrée de ce rappel est toujours comprise double
entre 0 et 1. Par conséquent, la ColorTo
méthode définit sa propre transformation Func
qui accepte un double
compris entre 0 et 1, et qui retourne une Color
valeur correspondant à cette valeur. La Color
valeur est calculée en interpolant les R
valeurs , G
, B
et A
des deux arguments fournis Color
. La Color
valeur est ensuite passée à la méthode de rappel pour application à une propriété particulière.
Cette approche permet à la ColorTo
méthode d’animer n’importe quelle Color
propriété, comme illustré dans l’exemple de code suivant :
await Task.WhenAll(
label.ColorTo(Color.Red, Color.Blue, c => label.TextColor = c, 5000),
label.ColorTo(Color.Blue, Color.Red, c => label.BackgroundColor = c, 5000));
await this.ColorTo(Color.FromRgb(0, 0, 0), Color.FromRgb(255, 255, 255), c => BackgroundColor = c, 5000);
await boxView.ColorTo(Color.Blue, Color.Red, c => boxView.Color = c, 4000);
Dans cet exemple de code, la ColorTo
méthode anime les TextColor
propriétés et BackgroundColor
d’un Label
, la BackgroundColor
propriété d’une page et la Color
propriété d’un BoxView
.