Search code examples
animationxamarin.formseasing

Animating the resizing of a boxview proportionally in Xamarin Forms


In my shared project I have a need for resizing a BoxView at the click of a button. It should preferably switch between taking up no space and 25% of any screen size proportionally, for which I'd usually use AbsoluteLayout.

I've tried using AbsoluteLayout and LayoutTo but since LayoutTo operates in pixels I've been unable to resize proportionally.

I've then change my solution to utilize Grid and a custom animation as seen in the code below.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:AnimationTest"
             x:Class="AnimationTest.MainPage">
    <Grid ColumnSpacing="0" RowSpacing="0">
        <Grid.RowDefinitions>
            <RowDefinition Height="9*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" x:Name="LeftColumn"/>
            <ColumnDefinition Width="3*"/>
        </Grid.ColumnDefinitions>

        <BoxView Color="DarkMagenta" Grid.Row="0" Grid.Column="0"/>

        <Button Text="Animate" Grid.Row="1" Grid.Column="1" Clicked="Button_Clicked"/>

    </Grid>
</ContentPage>

and the codebehind

namespace AnimationTest
{
    public partial class MainPage : ContentPage
    {
        Animation _animation;
        bool _boxCollapsed = false;

        public MainPage()
        {
            InitializeComponent();
        }

        private void Button_Clicked(object sender, EventArgs e)
        {
            switch (_boxCollapsed)
            {
                case true:
                    _animation = new Animation(
                    (d) => LeftColumn.Width = new GridLength(1, GridUnitType.Star));
                    _animation.Commit(this, "the animation", 16, 1000, Easing.SinIn, null, null);
                    _boxCollapsed = false;
                    break;
                case false:
                    _animation = new Animation(
                    (d) => LeftColumn.Width = new GridLength(0, GridUnitType.Star));
                    _animation.Commit(this, "the animation", 16, 1000, Easing.SinIn, null, null);
                    _boxCollapsed = true;
                    break;
            }
        }
    }
}

This has presented two issues though.

While currently not a problem this solution obviously resizes the entire column and not just the BoxView which could potentially become a problem at later stages. The second issue is that it seems to ignore the Easing parameter and just instantly goes between the two widthswithout actually animating.

I'm hoping someone can at the least inform me of what the issue is regarding the Easing or come up with a different and hopefully more elegant solution.


Solution

  • you'll just have to change a little bit the code on the animation line, i already give you hint on how to get the 25% of screen size. Hope it helps.

    private void Button_Clicked(object sender, EventArgs e)
        {
            var twentyFivePercentOfScreen = this.Width * .25;
    
            switch (_boxCollapsed)
            {
                case true:
                    _animation = new Animation(
                        (d) => LeftColumn.Width = d, 0, twentyFivePercentOfScreen);
                    _animation.Commit(this, "the animation", 16, 250, Easing.SinIn, null, null);
                    _boxCollapsed = false;
                    break;
                case false:
                    _animation = new Animation(
                        (d) => LeftColumn.Width = d, twentyFivePercentOfScreen, 0);
                    _animation.Commit(this, "the animation", 16, 250, Easing.SinIn, null, null);
                    _boxCollapsed = true;
                    break;
            }
        }