Oleg Vaskevich Oleg Vaskevich - 6 months ago 24
Android Question

SlidingPaneLayout: slide without smooth animation?

I'm using the new

SlidingPaneLayout
available in the latest support library, which provides the
openPane()
and
closePane()
methods to smooth open and close the panel. Unfortunately, there are no public methods to do so without animation.

Is there a way to still do this? I have a feeling reflection may be necessary.

P.S. The file is available under
sdk/extras/android/support/v4/src/java/android/support/v4/widget/
.

Answer

I ended up writing a subclass that provides two methods, openPaneNoAnimation() and closePaneNoAnimation(). Yes, it's reflection, and may stop working with future support libraries, but for now it does the job. Worst case, the methods fall back to using openPane() and closePane().

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import android.content.Context;
import android.support.v4.widget.SlidingPaneLayout;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class AnimationlessSlidingPaneLayout extends SlidingPaneLayout {
    private boolean mSlideEnabled = true;
    private Field mSlideOffsetField = null;
    private Field mSlideableViewField = null;
    private Method updateObscuredViewsVisibilityMethod = null;
    private Method dispatchOnPanelOpenedMethod = null;
    private Method dispatchOnPanelClosedMethod = null;
    private Field mPreservedOpenStateField = null;
    private Method parallaxOtherViewsMethod = null;

    public AnimationlessSlidingPaneLayout(Context context) {
        this(context, null, 0);
    }

    public AnimationlessSlidingPaneLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AnimationlessSlidingPaneLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        try {
            mSlideOffsetField = SlidingPaneLayout.class.getDeclaredField("mSlideOffset");
            mSlideableViewField = SlidingPaneLayout.class.getDeclaredField("mSlideableView");
            updateObscuredViewsVisibilityMethod = SlidingPaneLayout.class.getDeclaredMethod("updateObscuredViewsVisibility",
                                                                                            View.class);
            dispatchOnPanelClosedMethod = SlidingPaneLayout.class.getDeclaredMethod("dispatchOnPanelClosed", View.class);
            dispatchOnPanelOpenedMethod = SlidingPaneLayout.class.getDeclaredMethod("dispatchOnPanelOpened", View.class);
            mPreservedOpenStateField = SlidingPaneLayout.class.getDeclaredField("mPreservedOpenState");
            parallaxOtherViewsMethod = SlidingPaneLayout.class.getDeclaredMethod("parallaxOtherViews", float.class);

            mSlideOffsetField.setAccessible(true);
            mSlideableViewField.setAccessible(true);
            updateObscuredViewsVisibilityMethod.setAccessible(true);
            dispatchOnPanelOpenedMethod.setAccessible(true);
            dispatchOnPanelClosedMethod.setAccessible(true);
            mPreservedOpenStateField.setAccessible(true);
            parallaxOtherViewsMethod.setAccessible(true);
        } catch (Exception e) {
            Log.w("ASPL", "Failed to set up animation-less sliding layout.");
        }
    }

    public void openPaneNoAnimation() {
        try {
            View slideableView = (View) mSlideableViewField.get(this);
            mSlideOffsetField.set(this, 1.0f);
            parallaxOtherViewsMethod.invoke(this, 1.0f);
            requestLayout();
            invalidate();
            dispatchOnPanelOpenedMethod.invoke(this, slideableView);
            mPreservedOpenStateField.set(this, true);
        } catch (Exception e) {
            openPane();
        }
    }

    public void closePaneNoAnimation() {
        try {
            View slideableView = (View) mSlideableViewField.get(this);
            mSlideOffsetField.set(this, 0.0f);
            parallaxOtherViewsMethod.invoke(this, 0.0f);
            requestLayout();
            invalidate();
            updateObscuredViewsVisibilityMethod.invoke(this, slideableView);
            dispatchOnPanelClosedMethod.invoke(this, slideableView);
            mPreservedOpenStateField.set(this, false);
        } catch (Exception e) {
            closePane();
        }
    }

}