Animate view sliding out of another view, pushing views below out of the way

nhaarman picture nhaarman · Dec 14, 2012 · Viewed 20.4k times · Source

I have a list of buttons. When I press a button, a View should slide in a downwards motion out of the button, like this:

Start:
enter image description here

Halfway:
enter image description here

End:
enter image description here

How would I go about this? The View that should slide out is bigger than the button, so first hiding the View behind the button and then sliding it downwards causes the View to be visible above the button. That should not happen.

Any ideas or examples on how to approach this?

Answer

Luis picture Luis · Dec 21, 2012

I believe the simplest approach is to extend Animation class and override applyTransformation() to change the view's height as follows:

import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.LinearLayout;

public class MyCustomAnimation extends Animation {

    public final static int COLLAPSE = 1;
    public final static int EXPAND = 0;

    private View mView;
    private int mEndHeight;
    private int mType;
    private LinearLayout.LayoutParams mLayoutParams;

    public MyCustomAnimation(View view, int duration, int type) {

        setDuration(duration);
        mView = view;
        mEndHeight = mView.getHeight();
        mLayoutParams = ((LinearLayout.LayoutParams) view.getLayoutParams());
        mType = type;
        if(mType == EXPAND) {
            mLayoutParams.height = 0;
        } else {
            mLayoutParams.height = LayoutParams.WRAP_CONTENT;
        }
        view.setVisibility(View.VISIBLE);
    }

    public int getHeight(){
        return mView.getHeight();
    }

    public void setHeight(int height){
        mEndHeight = height;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {

        super.applyTransformation(interpolatedTime, t);
        if (interpolatedTime < 1.0f) {
            if(mType == EXPAND) {
                mLayoutParams.height =  (int)(mEndHeight * interpolatedTime);
            } else {
                mLayoutParams.height = (int) (mEndHeight * (1 - interpolatedTime));
            }
            mView.requestLayout();
        } else {
            if(mType == EXPAND) {
                mLayoutParams.height = LayoutParams.WRAP_CONTENT;
                mView.requestLayout();
            }else{
                mView.setVisibility(View.GONE);
            }
        }
    }
}

To use it, set your onclick() as follows:

int height;

@Override
public void onClick(View v) {
    if(view2.getVisibility() == View.VISIBLE){
        MyCustomAnimation a = new MyCustomAnimation(view2, 1000, MyCustomAnimation.COLLAPSE);
        height = a.getHeight();
        view2.startAnimation(a);
    }else{
        MyCustomAnimation a = new MyCustomAnimation(view2, 1000, MyCustomAnimation.EXPAND);
        a.setHeight(height);
        view2.startAnimation(a);
    }
}

Regards.