Números animados en dotNet MAUI

En esta ocasión os traigo un truco sencillo sobre cómo crear una animación vistosa a la hora de mostrar datos numéricos, como pueden ser valores estadísticos, importes…

Para ello, he creado un ejemplo con un control, que recibe un valor, un string format y el tiempo, en milisegundos, que debe durar la animación.
Si inspeccionamos el control, vemos que tiene una bindable property por cada uno de los valores expuestos.
public static readonly BindableProperty ValueProperty = BindableProperty.Create(nameof(Value), typeof(decimal), typeof(AnimatedValue), defaultValue: 0m, defaultBindingMode: BindingMode.OneWay, propertyChanged: ValueChanged);
public static readonly BindableProperty FormatProperty = BindableProperty.Create(nameof(Format), typeof(string), typeof(AnimatedValue), defaultBindingMode: BindingMode.OneWay, propertyChanged: FormatChanged);
public static readonly BindableProperty DurationProperty = BindableProperty.Create(nameof(Duration), typeof(uint), typeof(AnimatedValue), defaultValue: (uint)1_000, defaultBindingMode: BindingMode.OneWay);
...
public decimal Value
{
get => (decimal)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public string Format
{
get => (string)GetValue(FormatProperty);
set => SetValue(FormatProperty, value);
}
public uint Duration
{
get => (uint)GetValue(DurationProperty);
set => SetValue(DurationProperty, value);
}
La interfaz de usuario de este control también es bien sencilla, ya que solamente tiene un label, que utilizaremos para mostrar el valor en su formato correspondiente.
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="NumberAnimation.AnimatedValue">
<Label
x:Name="lbNumber"
FontSize="32"
VerticalOptions="Center"
HorizontalOptions="Center" />
</ContentView>
Por último, hay que destacar el funcionamiento del control. Siempre que cambia el valor, se lanza una animación, cancelándose previamente la anterior, por si todavía se está ejecutando.
private const string ANIMATION_NAME = "NumberAnimation";
private void ExecuteAnimation(double start, double end)
{
this.AbortAnimation(ANIMATION_NAME);
Animation animation = new Animation(x => lbNumber.Text = x.ToString(Format), start, end, null, () => lbNumber.Text = end.ToString(Format));
animation.Commit(this, ANIMATION_NAME, 16, Duration);
}
private static void ValueChanged(BindableObject bindable, object oldValue, object newValue)
{
double start = Decimal.ToDouble((decimal)oldValue);
double end = Decimal.ToDouble((decimal)newValue);
((AnimatedValue)bindable).ExecuteAnimation(start, end);
}
Del mismo modo, si cambia el formato, se actualiza el texto del label para reflejarlo.
private static void FormatChanged(BindableObject bindable, object oldValue, object newValue)
{
((AnimatedValue)bindable).lbNumber.Text = ((AnimatedValue)bindable).Value.ToString((string)newValue);
}
Notese, que si cambia la duranción de la animación no se hace nada, ya que se tendrá en cuenta al ejecutar la siguiente animación.
Al igual que en otras ocasiones, el código de este ejemplo está disponible en mi repositorio de Github https://github.com/jorgediegocrespo/MauiNumberAnimation
Foto de Nick Hillier en Unsplash