Tuesday, February 17, 2015

Dipping your feet into Xamarin Animation Extensions

I must admit that I've kind of missed this whole animation thingy that Xamarin put into Xamarin Forms. I've used the Animation classes to animate single properties, but haven't really put any time into exploring the extension methods for the View class. (poorly documented here).

The animation extension methods lets you move, rotate and scale stuff with different duration and easing functions. Duration and easing are optional parameters that you can pass into each animation function. An easing is a function of the rate of change during an animation. For example the BounceIn easing will overshoot its target and "bounce back" to the value required. Hence, bounce...

Anyway, let's move through each function!

The sandbox

So I started out with a single button in a single XAML view. Centered in all directions and just perfect. I've totally ignored all MVVM stuff and directly referenced the button control by name (theButton).

xml version="1.0" encoding="UTF-8"?>
<ContentPage 
    xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    x:Class="AnimateThis.MainView">

    <ContentPage.Content>
        <Button Text="Click me" x:Name="theButton" 
                VerticalOptions="Center" 
                HorizontalOptions="Center" />
    </ContentPage.Content>
</ContentPage>



Step one - Let's move it!

I added code in the code behind to handle the Click event (don't worry, we'll do it MVVM style later on in another post). This simply moves the button itself to a absolute position. You could of course move any other object that inherits from VisualElement. An important thing to think about is that it will move the object to the bounding box's upper left corner. Also, you must supply enough space yourself to make sure that the contents of the view has enough room to display itself.

    public partial class MainView : ContentPage
    {
        public MainView()
        {
            InitializeComponent();
            theButton.Clicked += async (object sender, EventArgs e) => 
                {
                   await theButton.LayoutTo(new Rectangle(100, 100, 300, 50));
                };
        }
    }

Step two - Translate this!

Another way to move the button without having to care about the width and height is to use the TranslateTo extension method. The important thing here is that the movement is relative. So translating by {0,0} doesn't do a thing. The example below moves the button left and up by 50.

    await theButton.TranslateTo(-50, -50);

In order to use the TranslateTo extension method you need to keep track of where you start from.

Step three - Scaling and ContinueWith!

You can string animations together since all calls are using async/await. The first way of doing this is to simply declare the method async and add await before each call. (gotta love C#).

    await theButton.ScaleTo(3);
    await theButton.ScaleTo(1);

So then this should work...

await theButton.ScaleTo(3).ContinueWith((a) => theButton.ScaleTo(1) );  

It does not... It works the first time you click the button, but the second time it gets stuck after the initial upscaling.

Step four - RelScale does what?

All the Rel* functions simply add to what ever value the control has before. The code below adds 4 to the scale each time you click it. It becomes really large after a while.

    await theButton.RelScaleTo(4);

This also goes for RelRotate and is pretty much what TranslateTo also does.

Step five - Fade to black

The fade function let's you control the opacity to what ever value you'd like. Nothing fancy, but very useful. To make the button disappear, just fade to 0. The upper limit is one (1) and that means that it's totally visible.

    await theButton.FadeTo(0);

Step six - Rotation

The last of the animation extension methods. Rotates the control to 40 absolute degrees. The RelRotate adds the given value to the current rotation.

   await theButton.RotateTo(40);

Another cool rotate function the RotateXTo and RotateYTo that gives you a 3D effect. Combine it with a FadeTo(0) to make your buttons fold and disappear! :)

Combining them

Can you combine different animations? Well, yes you can! Simply omit the await keyword to continue execution.

   theButton.TranslateTo(-10, -150);
   await theButton.FadeTo(0);

You might wonder why I don't use a fancier way to do the await, like in the example below? It simply doesn't work. The animation "locks up" half way through. Another issue for Bugzilla.

   var t1 = theButton.TranslateTo(-10, -150);
   var t2 = theButton.FadeTo(0);

   Task.WaitAll(t1, t2);

Summary

The animation extension methods are cool. Use them. Now!

6 comments:

  1. This blog post will be on this weeks www.XamarinWeekly.com newsletter issue #27. Comes out tomorrow morning.

    ReplyDelete
  2. For the last example, have you tried with "await Task.WhenAll (tasks);"
    It works on me for FadeTo 2 buttons at the same time.

    ReplyDelete
    Replies
    1. Thanks for the feedback! Most likely the bug has been fixed since the publishing of this article. Good news! :)

      Delete
  3. How do you setup an animation to play automatically? When I set these up outside of a click event they default to the new set values and ignore the timing/animation portion.

    ReplyDelete
  4. Avoid utilizing words that are excessively convoluted. Keep in mind that your gathering of people is the children; and there's no child who'll need to allude your words from the lexicon. To be additionally engaging, utilize words that can be understood by a review six understudy. great post to read

    ReplyDelete