/ XAMARIN

Simple Animation with Xamarin.Forms

Those of you know me (or have visited my blog) know that I love playing around with Xamarin.Forms Layouts.   Recently, Matt Soucoup was on the Xamarin Show talking about Animations. He showed how easy it is to do simple animations in Xamarin Forms. Personally, I don’t think developers do enough with animations – they can really spice up your UI and show your users how much you care.

I thought it might be fun to use some of the stuff that Matt was talking about and put it into a more real world context.

I also came across an excellent blog post Build awesome animations with 7 lines of code using ConstraintLayout which is great if you are doing Android development. So just for giggles, I thought I might reproduce that animations in Xamarin Forms – It took slightly more than 7 lines, but having said that, it also works cross platform.

The animation itself, is very simple and looks a lot like this:

 

and on iOS, like this:

 

So how do we go about doing something like that?

The Page Layout

<ContentPage x:Class="Animation.AnimationPage" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Animation" xmlns:views="clr-namespace:Animation.Views" BackgroundColor="#181818">

    <Grid Padding="0" ColumnSpacing="0" RowSpacing="0">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="AUTO" />
        </Grid.RowDefinitions>

        <Image x:Name="MainImage" Grid.Row="0" Grid.RowSpan="2" Aspect="AspectFill" Source="mugello.jpg">
            <Image.GestureRecognizers>
                <TapGestureRecognizer NumberOfTapsRequired="1" Tapped="Handle_Tapped" />
            </Image.GestureRecognizers>
        </Image>

        <views:ExpandBar x:Name="ExpandBar" Grid.Row="1" Padding="0" TranslationY="1" VerticalOptions="End" />

        <views:DescriptionPane x:Name="BottomFrame" Grid.Row="1" IsVisible="true" Text="The Mugello is a historic region and valley in northern Tuscany, in Italy. It is located to the north of the city of Florence and consists of the northernmost portion of the Metropolitan City of Florence.  It is connected to the separate Santerno river valley by the Futa Pass." VerticalOptions="End" />

        <views:Title x:Name="Title" Grid.Row="0" Margin="0,40,0,0" HorizontalOptions="Start" VerticalOptions="Start" />
    </Grid>
</ContentPage>

Nothing too exciting happening here. Just a ContentPage with a grid inside with a few overlapped elements. I’ve made put each element that will be animated into a ContentView so that I can move all it’s sub elements by just controlling the animations on the ContentViews. There is also a GestureRecognizer on the Image which is actually going to trigger the animations.

As an aside, I used grids to lay this out (because I loves me some grids), but if you were a fan of AbsoluteLayout you could probably achieve the same result with that.

The Animation Logic

We can achieve the results we are after with just some very simple inbuilt Xamarin.Forms animations, specifically we use:

  • LayoutTo to adjust the bounds of the Image (to make it expand and shrink)
  • TranslateTo to slide elements around
  • FadeTo to fade opacity values

Throw in some Easing on those animations to provide a nice spring effect and we are in business. Here is the code that does the animation:

void Handle_Tapped(object sender, System.EventArgs e)
{
    if (isExpanded)
        AnimateIn();
    else
        AnimateOut();

    isExpanded = !isExpanded;
}

private void AnimateIn()
{
    MainImage.LayoutTo(detailsRect, 1200, Easing.SpringOut);
    BottomFrame.TranslateTo(0, 0, 1200, Easing.SpringOut);
    Title.TranslateTo(0, 0, 1200, Easing.SpringOut);
    ExpandBar.FadeTo(.01, 250, Easing.SinInOut);
}

private void AnimateOut()
{
    MainImage.LayoutTo(expandedRect, 1200, Easing.SpringOut);
    BottomFrame.TranslateTo(0, BottomFrame.Height, 1200, Easing.SpringOut);
    Title.TranslateTo(-Title.Width, 0, 1200, Easing.SpringOut);
    ExpandBar.FadeTo(1, 250, Easing.SinInOut);
}

Starting State

The only other bit of significant logic (and it’s not that significant) is just starting all the elements in their correct starting positions. I’ve done this on the OnSizeAllocated because then we can also handle positioning things in the correct locations on a rotation of the device. Again the code is super simple:

protected override void OnSizeAllocated(double width, double height)
{
    base.OnSizeAllocated(width, height);

    // cache the bounds for the image so I don't repeat calculations everywhere
    detailsRect = new Rectangle(0, 0, width, BottomFrame.Bounds.Top + 20);
    expandedRect = new Rectangle(0, 0, width, height);

    // move things to their starting point
    if (isExpanded)
    {
        MainImage.Layout(expandedRect);
        BottomFrame.TranslationY = BottomFrame.Height;
        Title.TranslationX = -Title.Width;
    }
    else
    {
        MainImage.Layout(detailsRect);
        BottomFrame.TranslationY = 0;
        Title.TranslationX = 0;
    }
}

Conclusion

You can achieve some pretty nice stuff with the inbuilt Xamarin.Forms animation api’s. And really this is just scratching the surface. My layout here could be much nicer with some attention to details on fonts and margins – but really I just wanted to focus in on the animations. So people, go out and add some animations to your pages!!!

Additional References

Oh yeah, I almost forgot, you can go find the code over at my GitHub here.

Until next time, happy coding!

kphillpotts

Kym Phillpotts

Geek, Parent, Human, Senior Content Developer at Microsoft. Co-curator of http://weeklyxamarin.com and twitch streaming live coding at http://twitch.tv/kymphillpotts.

Read More