Search code examples
androidandroid-fragmentsxamarinandroid-custom-viewandroid-transitions

How to create custom views with properties for animating in Xamarin


I'm trying to add custom transition to fragments. As the Link suggested , the proper solution is to create a custom view as fragment container and then by animating the new added property , make fragment's transition run. but absolutely its on java. I implemented that as below in C# and Xamarin:

class SmartFrameLayout : FrameLayout
{

    public SmartFrameLayout(Context context) : base(context) { }
    public SmartFrameLayout(Context context, IAttributeSet attrs) : base(context, attrs) { }
    public SmartFrameLayout(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr) { }
    public SmartFrameLayout(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes) { }

    //public float getXFraction()
    //{
    //    if (Width == 0) return 0;
    //    return GetX() / Width;
    //}

    //public void setXFraction(float fraction)
    //{
    //    Log.Debug("Fraction", fraction.ToString());
    //    float xx = GetX();
    //    SetX(xx * fraction);
    //}

    //private float XFraction;


    public float XFraction
    {
        get {
            if (Width == 0) return 0;
            return GetX() / Width;
        }
        set {
            float xx = GetX();
            SetX(xx * value);
        }
    }

}

As you can see, first I tried to implement that same as the tutorial (Except that c# doesn't support read-only local variable as a "final" replacement!) but in objectAnimator the property did not called properly. Then I think maybe using C# property will solve the problem. But it didn't.

Here is my animation xml file, named "from_right.xml":

<?xml version="1.0" encoding="utf-8" ?>
<objectAnimator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:propertyName="xFraction"
    android:valueType="floatType"
    android:valueFrom="1.0"
    android:valueTo="0"
    android:duration="500"/>

I changed propertyName to "XFraction" or even anything else, but the results was the same.

Using "x" as propertyName and "1000" as valueFrom works well.

So I figured out the main problem is that the objectAnimator could not call setXFraction at all!

Please tell me what I'm doing wrong, or if there is a better solution to get exactly the screen width for valueFrom in objectAnimator !


Solution

  • You need to expose the setXFraction and getXFraction methods to Java; they are currently only within managed code and are not accesible to the Java VM.

    Use the [Export] attribute to expose these methods to Java so that the animator can use them:

        [Export]
        public float getXFraction()
        {
            if (Width == 0) return 0;
            return GetX() / Width;
        }
    
        [Export]
        public void setXFraction(float fraction)
        {
            Log.Debug("Fraction", fraction.ToString());
            float xx = GetX();
            SetX(xx * fraction);
        }
    

    This will result in the following Java code being generated in SmartFrameLayouts Android Callable Wrapper:

    public float getXFraction ()
    {
        return n_getXFraction ();
    }
    
    private native float n_getXFraction ();
    
    
    public void setXFraction (float p0)
    {
        n_setXFraction (p0);
    }
    
    private native void n_setXFraction (float p0);