Search code examples
androidandroid-layoutxamarin.androidandroid-animationandroid-layoutparams

Animate LayoutParams LeftMargin and TopMargin


I've read on how to do this in Android, but I cannot seem to find the Xamarin Android equivalent to animating a Layout's LeftMargin and TopMargin. Obviously Xamarin has "Animation", but I can't figure out the "applyTransformation" part of this in Xamarin where I set my "newLeftMargin * interpolatedTime".

Here is the standard Android reference: Android - Change left margin using animation

Animation a = new Animation();
//applyTransformation???? with "newLeftMargin * interpolatedTime"
a.Duration = 500;
MyThingy.StartAnimation(a);

Thanks to user Apineda for providing the answer. Here is the code I ended up writing in case anyone wants it. The first constructor animates the margins from their current state, rather than just from zero. The second constructor requires you to specify start margins.

class LayoutMarginAnimation : Android.Views.Animations.Animation
{
    private ViewGroup ViewToTransform;
    private int LeftMargin_Destination;
    private int TopMargin_Destination;
    private int LeftMargin_Source;
    private int TopMargin_Source;

    /// <summary>
    /// Animates a layout from it's current margins to specified margins
    /// </summary>
    /// <param name="a_viewToTransform">A view to transform.</param>
    /// <param name="a_LeftMargin_Destination">A left margin destination.</param>
    /// <param name="a_TopMargin_Destination">A top margin destination.</param>
    public LayoutMarginAnimation(
        ViewGroup a_viewToTransform,
        int a_LeftMargin_Destination,
        int a_TopMargin_Destination
    )
    {
        this.ViewToTransform = a_viewToTransform;
        this.LeftMargin_Destination = a_LeftMargin_Destination;
        this.TopMargin_Destination = a_TopMargin_Destination;

        this.LeftMargin_Source = (this.ViewToTransform.LayoutParameters as RelativeLayout.LayoutParams).LeftMargin;
        this.TopMargin_Source = (this.ViewToTransform.LayoutParameters as RelativeLayout.LayoutParams).TopMargin;
    }

    /// <summary>
    /// Animates a layout from specified margins to specified margins, regardless of what the margins are currently set to.  
    /// </summary>
    /// <param name="a_viewToTransform">A view to transform.</param>
    /// <param name="a_LeftMargin_Source">A left margin source.</param>
    /// <param name="a_TopMargin_Source">A top margin source.</param>
    /// <param name="a_LeftMargin_Destination">A left margin destination.</param>
    /// <param name="a_TopMargin_Destination">A top margin destination.</param>
    public LayoutMarginAnimation(
        ViewGroup a_viewToTransform,
        int a_LeftMargin_Source,
        int a_TopMargin_Source,
        int a_LeftMargin_Destination,
        int a_TopMargin_Destination
    )
    {
        this.ViewToTransform = a_viewToTransform;
        this.LeftMargin_Destination = a_LeftMargin_Destination;
        this.TopMargin_Destination = a_TopMargin_Destination;
        this.LeftMargin_Source = a_LeftMargin_Source;
        this.TopMargin_Source = a_TopMargin_Source;
    }

    protected override void ApplyTransformation(float interpolatedTime, Transformation t)
    {
        //Console.WriteLine("ApplyTransformation with interpolatedTime = " + interpolatedTime);
        RelativeLayout.LayoutParams layoutParams = this.ViewToTransform.LayoutParameters as RelativeLayout.LayoutParams;

        layoutParams.LeftMargin = this.LeftMargin_Source + (int)((this.LeftMargin_Destination - this.LeftMargin_Source) * interpolatedTime);
        layoutParams.TopMargin = this.TopMargin_Source + (int)((this.TopMargin_Destination - this.TopMargin_Source) * interpolatedTime);

        this.ViewToTransform.LayoutParameters = layoutParams;
    }
}

And here's how to call both constructors.

            // Animates a layout from it's current margins to specified margins
            LayoutMarginAnimation animation = new LayoutMarginAnimation(this.DraggableSeedImageContainer, 1000, 1000);
            // Animates a layout from specified margins to specified margins, regardless of what the margins are currently set to.
            //LayoutMarginAnimation animation = new LayoutMarginAnimation(this.DraggableSeedImageContainer, 200, 200, 1000, 1000);
            animation.Duration = 500;
            this.DraggableSeedImageContainer.StartAnimation(animation);

Solution

  • you are having issues to do it that's because the Animation class is an abstract class. You have to create your own implementation and override the ApplyTransformation() method.

    Using the link you provided to translate it to Xamarin.Android we have:

    My custom animation class:

    class ViewLeftMargingAnimation : Animation
    {
        View _viewToTransform;
    
        int _newLeftMargin;
    
        public ViewLeftMargingAnimation (View viewToTransform, int newLeftMargin)
        {
            _viewToTransform = viewToTransform;
    
            _newLeftMargin = newLeftMargin;
        }
    
        protected override void ApplyTransformation (float interpolatedTime, Transformation t)
        {
            var layoutParams = (LinearLayout.LayoutParams)_viewToTransform.LayoutParameters;
            layoutParams.LeftMargin = (int)(_newLeftMargin * interpolatedTime);
            _viewToTransform.LayoutParameters = layoutParams;
        }
    }
    

    Using your Animation:

    // View that will be animated:
    var button = FindViewById<Button> (Resource.Id.myButton);
    
    // Animation object:
    var a = new ViewLeftMargingAnimation (button, 150);
    
    // Animation's duration:
    a.Duration = 500;
    
    // Start my animation 
    button.StartAnimation (a);
    

    This could also be possible using the ValueAnimator class. More about Xamarin.Android animations here.