Animaciones simples en Xamarin.Forms
La clase ViewExtensions proporciona métodos de extensión que se pueden usar para construir animaciones simples. En este artículo se muestra cómo crear y cancelar animaciones mediante la clase ViewExtensions.
La clase ViewExtensions
proporciona los siguientes métodos de extensión que se pueden usar para crear animaciones sencillas:
CancelAnimations
cancela todas las animaciones.FadeTo
anima la propiedadOpacity
de unVisualElement
.RelScaleTo
aplica un aumento o disminución incremental animado a la propiedadScale
de unVisualElement
.RotateTo
anima la propiedadRotation
de unVisualElement
.RelRotateTo
aplica un aumento o disminución incremental animado a la propiedadRotation
de unVisualElement
.RotateXTo
anima la propiedadRotationX
de unVisualElement
.RotateYTo
anima la propiedadRotationY
de unVisualElement
.ScaleTo
anima la propiedadScale
de unVisualElement
.ScaleXTo
anima la propiedadScaleX
de unVisualElement
.ScaleYTo
anima la propiedadScaleY
de unVisualElement
.TranslateTo
anima las propiedadesTranslationX
yTranslationY
de unVisualElement
.
De manera predeterminada, cada animación tardará 250 milisegundos. Sin embargo, al crear la animación se puede especificar su duración.
Nota:
La clase ViewExtensions
proporciona un método de extensión LayoutTo
. Sin embargo, este método está pensado para ser utilizado por los diseños para animar transiciones entre estados de diseño que contienen cambios de tamaño y posición. Por lo tanto, solo debe usarse en subclases Layout
.
Los métodos de extensión de animación de la clase ViewExtensions
son asincrónicos y devuelven un objeto Task<bool>
. El valor devuelto es false
si la animación se completa y true
si se cancela la animación. Por lo tanto, los métodos de animación normalmente deben usarse con el operador await
, lo que permite determinar fácilmente cuándo se ha completado una animación. Además, es posible crear animaciones secuenciales con métodos de animación posteriores que se ejecutan después de que se haya completado el método anterior. Para obtener más información, vea Animaciones compuestas.
Si hay un requisito para permitir que una animación se complete en segundo plano, se puede omitir el operador await
. En este escenario, los métodos de extensión de animación volverán rápidamente después de iniciar la animación, con la animación que se produce en segundo plano. Esta operación se puede aprovechar al crear animaciones compuestas. Para obtener más información, consulte Animaciones compuestas.
Para obtener más información sobre el operador await
, consulte Introducción a la compatibilidad asincrónica.
Animaciones únicas
Cada método de extensión del ViewExtensions
implementa una única operación de animación que cambia progresivamente una propiedad de un valor a otro durante un período de tiempo. En esta sección se explora cada operación de animación.
Rotación
En el ejemplo de código siguiente se muestra el uso del método RotateTo
para animar la propiedad Rotation
de un Image
:
await image.RotateTo (360, 2000);
image.Rotation = 0;
Este código anima la instancia de Image
girando hasta 360 grados durante 2 segundos (2000 milisegundos). El método RotateTo
obtiene el valor de la propiedad Rotation
actual para el inicio de la animación y, a continuación, gira desde ese valor a su primer argumento (360). Una vez completada la animación, la propiedad Rotation
de la imagen se restablece en 0. Esto garantiza que la propiedad Rotation
no permanezca en 360 después de que finalice la animación, lo que impediría rotaciones adicionales.
Las capturas de pantalla siguientes muestran el giro en curso en cada plataforma:
Nota:
Además del método RotateTo
, también hay métodos RotateXTo
y RotateYTo
que animan las propiedades RotationX
y RotationY
, respectivamente.
Giro relativo
En el ejemplo de código siguiente se muestra el uso del método RelRotateTo
para aumentar o disminuir incrementalmente la propiedad Rotation
de un Image
:
await image.RelRotateTo (360, 2000);
Este código anima la instancia de Image
girando 360 grados desde su posición inicial durante 2 segundos (2000 milisegundos). El método RelRotateTo
obtiene el valor de la propiedad Rotation
actual para el inicio de la animación y, a continuación, gira desde ese valor hasta el valor más su primer argumento (360). Esto garantiza que cada animación será siempre una rotación de 360 grados desde la posición inicial. Por lo tanto, si se invoca una nueva animación mientras una animación ya está en curso, comenzará desde la posición actual y puede terminar en una posición que no sea un incremento de 360 grados.
Las capturas de pantalla siguientes muestran el giro relativo en curso en cada plataforma:
Ampliación
En el ejemplo de código siguiente se muestra el uso del método ScaleTo
para animar la propiedad Scale
de un Image
:
await image.ScaleTo (2, 2000);
Este código anima la instancia de Image
mediante el escalado vertical hasta dos veces su tamaño durante 2 segundos (2000 milisegundos). El método ScaleTo
obtiene el valor de propiedad Scale
actual (valor predeterminado de 1) para el inicio de la animación y, a continuación, escala desde ese valor a su primer argumento (2). Esto tiene el efecto de expandir el tamaño de la imagen a dos veces su tamaño.
Las capturas de pantalla siguientes muestran el escalado en curso en cada plataforma:
Nota:
Además del método ScaleTo
, también hay métodos ScaleXTo
y ScaleYTo
que animan las propiedades ScaleX
y ScaleY
, respectivamente.
Escalado relativo
En el ejemplo de código siguiente se muestra el uso del método RelScaleTo
para animar la propiedad Scale
de un Image
:
await image.RelScaleTo (2, 2000);
Este código anima la instancia de Image
mediante el escalado vertical hasta dos veces su tamaño durante 2 segundos (2000 milisegundos). El método RelScaleTo
obtiene el valor de la propiedad Scale
actual para el inicio de la animación y, a continuación, escala desde ese valor hasta el valor más su primer argumento (2). Esto garantiza que cada animación siempre será un escalado de 2 desde la posición inicial.
Escalado y giro con anclajes
Las propiedades AnchorX
y AnchorY
establecen el centro de escalado o giro de las propiedades Rotation
y Scale
. Por lo tanto, sus valores también afectan a los métodos RotateTo
y ScaleTo
.
Dado que Image
se ha colocado en el centro de un diseño, el siguiente ejemplo de código muestra la rotación de la imagen alrededor del centro del diseño estableciendo su propiedad AnchorY
:
double radius = Math.Min(absoluteLayout.Width, absoluteLayout.Height) / 2;
image.AnchorY = radius / image.Height;
await image.RotateTo(360, 2000);
Para girar la instancia Image
alrededor del centro del diseño, las propiedades AnchorX
y AnchorY
deben establecerse en valores que sean relativos a lo ancho y alto de Image
. En este ejemplo, el centro de Image
se define para que esté en el centro del diseño y, por tanto, el valor predeterminado AnchorX
de 0,5 no necesita cambiarse. Sin embargo, la propiedad AnchorY
se vuelve a definir como un valor desde la parte superior de Image
hasta el punto central del diseño. Esto garantiza que el Image
realice un giro completo de 360 grados alrededor del punto central del diseño, como se muestra en las capturas de pantalla siguientes:
Traducción
En el ejemplo de código siguiente se muestra el uso del método TranslateTo
para animar las propiedades TranslationX
y TranslationY
de un Image
:
await image.TranslateTo (-100, -100, 1000);
Este código anima la instancia de Image
trasladándola horizontal y verticalmente durante 1 segundo (1000 milisegundos). El método TranslateTo
traslada simultáneamente la imagen de 100 píxeles a la izquierda y 100 píxeles hacia arriba. Esto se debe a que los argumentos primero y segundo son números negativos. Proporcionar números positivos traduciría la imagen a la derecha y hacia abajo.
Las capturas de pantalla siguientes muestran el traslado en curso en cada plataforma:
Nota:
Si un elemento se coloca inicialmente fuera de la pantalla y, después, se traduce en la pantalla, después de traducirse, el diseño de entrada del elemento permanece fuera de la pantalla y el usuario no puede interactuar con él. Por lo tanto, se recomienda que una vista se diseñe en su posición final y, después, se realicen las traducciones necesarias.
Corrección selectiva
En el ejemplo de código siguiente se muestra el uso del método FadeTo
para animar la propiedad Opacity
de un Image
:
image.Opacity = 0;
await image.FadeTo (1, 4000);
Este código anima la instancia de Image
atenuándola en más de 4 segundos (4000 milisegundos). El método FadeTo
obtiene el valor de propiedad Opacity
actual para el inicio de la animación y, a continuación, se atenúa desde ese valor a su primer argumento (1).
Las capturas de pantalla siguientes muestran la atenuación en curso en cada plataforma:
Animaciones compuestas
Una animación compuesta es una combinación secuencial de animaciones y se puede crear con el operador await
, como se muestra en el ejemplo de código siguiente:
await image.TranslateTo (-100, 0, 1000); // Move image left
await image.TranslateTo (-100, -100, 1000); // Move image diagonally up and left
await image.TranslateTo (100, 100, 2000); // Move image diagonally down and right
await image.TranslateTo (0, 100, 1000); // Move image left
await image.TranslateTo (0, 0, 1000); // Move image up
En este ejemplo, Image
se traslada más de 6 segundos (6000 milisegundos). La traducción de Image
utiliza cinco animaciones, con el operador await
que indica que cada animación se ejecuta secuencialmente. Por lo tanto, los métodos de animación posteriores se ejecutan después de que se haya completado el método anterior.
Animaciones compuestas
Una animación compuesta es una combinación de animaciones en las que dos o más animaciones se ejecutan simultáneamente. Las animaciones compuestas se pueden crear mezclando animaciones esperadas y no esperadas, como se muestra en el ejemplo de código siguiente:
image.RotateTo (360, 4000);
await image.ScaleTo (2, 2000);
await image.ScaleTo (1, 2000);
En este ejemplo, el Image
se escala y se gira simultáneamente durante 4 segundos (4000 milisegundos). El escalado de Image
utiliza dos animaciones secuenciales que se producen al mismo tiempo que la rotación. El método RotateTo
se ejecuta sin ningún operador await
y vuelve inmediatamente, con la primera ScaleTo
animación que comienza. El operador await
en la primera llamada de método ScaleTo
retrasa la segunda llamada de método ScaleTo
hasta que se haya completado la primera llamada de método ScaleTo
. En este punto, la animación RotateTo
se completa a mitad de camino y el Image
se girará 180 grados. Durante los últimos 2 segundos (2000 milisegundos), la segunda animación ScaleTo
y la animación RotateTo
se completan.
Ejecutar varios métodos asincrónicos simultáneamente
Los static
Task.WhenAny
métodos y Task.WhenAll
se usan para ejecutar varios métodos asincrónicos simultáneamente y, por tanto, se pueden usar para crear animaciones compuestas. Ambos métodos devuelven un objeto Task
y aceptan una colección de métodos que devuelven un objeto Task
. El método Task.WhenAny
se completa cuando cualquier método de su colección completa la ejecución, tal como se muestra en el ejemplo de código siguiente:
await Task.WhenAny<bool>
(
image.RotateTo (360, 4000),
image.ScaleTo (2, 2000)
);
await image.ScaleTo (1, 2000);
En este ejemplo, la llamada de método Task.WhenAny
contiene dos tareas. La primera tarea gira la imagen durante 4 segundos (4000 milisegundos) y la segunda tarea escala la imagen durante 2 segundos (2000 milisegundos). Cuando se completa la segunda tarea, se completa la llamada al método Task.WhenAny
. Sin embargo, aunque el método RotateTo
siga en ejecución, el segundo método ScaleTo
puede comenzar.
El método Task.WhenAll
se completa cuando se han completado todos los métodos de su colección, como se muestra en el ejemplo de código siguiente:
// 10 minute animation
uint duration = 10 * 60 * 1000;
await Task.WhenAll (
image.RotateTo (307 * 360, duration),
image.RotateXTo (251 * 360, duration),
image.RotateYTo (199 * 360, duration)
);
En este ejemplo, la llamada de método Task.WhenAll
contiene tres tareas, cada una de las cuales se ejecuta durante 10 minutos. Cada Task
hace un número diferente de rotaciones de 360 grados: 307 rotaciones para RotateTo
, 251 rotaciones para RotateXTo
y 199 rotaciones para RotateYTo
. Estos valores son números primos, con lo que se garantiza que las rotaciones no están sincronizadas y, por tanto, no darán lugar a patrones repetitivos.
En las capturas de pantalla siguientes se muestran los múltiples giros en curso en cada plataforma:
Cancelación de animaciones
Una aplicación puede cancelar una o varias animaciones con una llamada al método de extensión CancelAnimations
, como se muestra en el ejemplo de código siguiente:
image.CancelAnimations();
Esto cancelará inmediatamente todas las animaciones que se ejecutan actualmente en la instancia de Image
.
Resumen
En este artículo se muestra cómo crear y cancelar animaciones mediante la clase ViewExtensions
. Esta clase proporciona métodos de extensión que se pueden usar para construir animaciones simples que giran, escalan, trasladan y atenúan instancias de VisualElement
.