Xamarin has done a great job on bringing async/await to animations on iOS (as Kerry shows on his blog) and on Xamarin.Forms. For my Fingerprint Plugin I was playing around with some animations on Android and I expected to find a similar animation extension - but I did not (If I’ve overseen something, tweet me). But, awaiting animations is pretty easy with a small extension method.
Problem
I want to colorize a icon, animate it and remove the color after the animation. In another use case I want to animate the icon and close the dialog afterwards.
Solution
The Android way would be to implement a IAnimatorListener
, set the color in its OnAnimationStart
method and reset it in OnAnimationEnd
. But with this approach the code isn’t readable linearly and you would have to implement a IAnimatorListener
for each use case. I wanted to write my Animation like this:
_icon.SetColorFilter(NegativeColor);
var shake = ObjectAnimator.OfFloat(_icon, "translationX", -10f, 10f);
shake.SetDuration(500);
shake.SetInterpolator(new CycleInterpolator(5));
await shake.StartAsync();
_icon.ClearColorFilter();
You only need these two classes and are ready to animate Android with C# style.
Extension
The AnimatorExtensions
only contains the StartAsync
method that you should use to start a animation. It adds a TaskAnimationListener
as listener, starts the animation and returns the a Task. The method can be used with all Animator classes (e.g. ObjectAnimator, AnimatorSet, ValueAnimator
)
public static class AnimatorExtensions
{
public static Task StartAsync(this Animator animator)
{
var listener = new TaskAnimationListener();
animator.AddListener(listener);
animator.Start();
return listener.Task;
}
}
TaskAnimationListener
The TaskAnimationListener
implements IAnimatorListener
and uses a TaskCompletionSource
to convert the events OnAnimationCancel
and OnAnimationEnd
to the Canceled or Completed states of a Task.
public class TaskAnimationListener : Java.Lang.Object, Animator.IAnimatorListener
{
private readonly TaskCompletionSource<int> _tcs;
public Task Task => _tcs.Task;
public TaskAnimationListener()
{
_tcs = new TaskCompletionSource<int>();
}
public void OnAnimationCancel(Animator animation)
{
_tcs.TrySetCanceled();
}
public void OnAnimationEnd(Animator animation)
{
_tcs.TrySetResult(0);
}
public void OnAnimationRepeat(Animator animation)
{
}
public void OnAnimationStart(Animator animation)
{
}
}
Result
Found a typo? Send me a pull request!