Horizontal expand animation starting from the center of another View to it left bound

Viewed 302

I'm trying to a make a horizontal fill animation from the center to the edges of a other view. First i have centralized the view that will do the expand animation on the center of the main view and then animate with a ScaleXTo to the main view width:

XAML code:

    <StackLayout Padding="16" Spacing="10">
    
        <Grid
            Margin="0,0,0,16">
            <BoxView
                x:Name="firstView"
                BackgroundColor="Blue"
                HorizontalOptions="Start"
                HeightRequest="30"
                WidthRequest="180" />
    
            <BoxView
                x:Name="secondView"
                BackgroundColor="Black"
                HeightRequest="10"
                Scale="1"
                HorizontalOptions="StartAndExpand"
                VerticalOptions="Center"
                WidthRequest="1" />
        </Grid>
    
        <Button
            Clicked="Button_OnClicked"
            Text="Animate!" />
    </StackLayout>

The code behind:

    private void Button_OnClicked(object sender, EventArgs e) {
        secondView.TranslationX = firstView.Bounds.Center.X;
        secondView.ScaleXTo(firstView.Width);
    }

When executed, the animated view becomes larger than the main view, as can be seen on the print below

Result

2 Answers

Update: Since you explained in the comment that you want animation to start from the centre, I am updating the answer. Looks like there is a bug in Xamarin with scaling, since for some values of the WidthRequest and ScaleX it works as expected. For example, this implementation can do the trick for you:

    private void Button_OnClicked(object sender, EventArgs e)
    {
        double scale = 6;
        double startWidth = firstView.Width / scale;
        secondView.TranslationX = firstView.Bounds.Center.X - startWidth / 2;
        secondView.WidthRequest = startWidth;
        secondView.ScaleXTo(scale, 1000);
    }

but it will not work for bigger values of scale, ie. it will go outside of the firstView. So, it is better to go with something like @Cfun proposed. The only problem with his solution is that it will expand secondView to the entire firstView. Also, I'm using Task, since yours Button_OnClicked is not async method:

        private void Button_OnClicked(object sender, EventArgs e)
        {
            var rectangle = new Rectangle(secondView.X, secondView.Y, firstView.Width, secondView.Height);
            secondView.TranslationX = firstView.Bounds.Center.X;
            Task translate = Task.Factory.StartNew(() => secondView.TranslateTo(rectangle.Left, 0, 500));
            Task layout = Task.Factory.StartNew(() => secondView.LayoutTo(rectangle, 500));
            Task.WaitAll(new[] { translate, layout });
        }

Old answer: If just horizontal filling is what you are trying to achieve, there is no need for translation and then scaling. You can just implement Button_OnClicked like this:

    private void Button_OnClicked(object sender, EventArgs e)
    {
        secondView.LayoutTo(new Rectangle(secondView.X, secondView.Y, firstView.Width, secondView.Height));
    }

You can achieve it with two animations running concurrently in order to have a smooth visual, translation and resizing (LayoutTo)

private async void Button_Clicked(object sender, EventArgs e)
{
    secondView.TranslationX = firstView.Bounds.Center.X;
    secondView.TranslateTo(firstView.Bounds.Left, 0, 500);
    await secondView.LayoutTo(firstView.Bounds, 500);
}
Related