Android animate drop down/up view proper

前端 未结 2 1887
滥情空心
滥情空心 2020-11-30 19:40

Okay I\'m trying to do a proper slide down animation. The view that slides down should push all views bellow it down in one smooth movement and again when it slides up all t

相关标签:
2条回答
  • 2020-11-30 20:03

    So I ended up doing it myself with some help from: https://stackoverflow.com/a/9112691/969325. If it had been android 3.0 (http://developer.android.com/guide/topics/graphics/animation.html) I could have used property animation, but its not so I had to do that myself.

    Here is what I ended up with:

    import android.view.View;
    import android.view.animation.Animation;
    import android.view.animation.Transformation;
    
    /**
     * Class for handling collapse and expand animations.
     * @author Esben Gaarsmand
     *
     */
    public class ExpandCollapseAnimation extends Animation {
        private View mAnimatedView;
        private int mEndHeight;
        private int mType;
    
        /**
         * Initializes expand collapse animation, has two types, collapse (1) and expand (0).
         * @param view The view to animate
         * @param duration
         * @param type The type of animation: 0 will expand from gone and 0 size to visible and layout size defined in xml. 
         * 1 will collapse view and set to gone
         */
        public ExpandCollapseAnimation(View view, int duration, int type) {
            setDuration(duration);
            mAnimatedView = view;
            mEndHeight = mAnimatedView.getLayoutParams().height;
            mType = type;
            if(mType == 0) {
                mAnimatedView.getLayoutParams().height = 0;
                mAnimatedView.setVisibility(View.VISIBLE);
            }
        }
    
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            if (interpolatedTime < 1.0f) {
                if(mType == 0) {
                    mAnimatedView.getLayoutParams().height = (int) (mEndHeight * interpolatedTime);
                } else {
                    mAnimatedView.getLayoutParams().height = mEndHeight - (int) (mEndHeight * interpolatedTime);
                }
                mAnimatedView.requestLayout();
            } else {
                if(mType == 0) {
                    mAnimatedView.getLayoutParams().height = mEndHeight;
                    mAnimatedView.requestLayout();
                } else {
                    mAnimatedView.getLayoutParams().height = 0;
                    mAnimatedView.setVisibility(View.GONE);
                    mAnimatedView.requestLayout();
                    mAnimatedView.getLayoutParams().height = mEndHeight;
                }
            }
        }
    }
    

    Example ussage:

    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    
    public class AnimationTestActivity extends Activity {
        private boolean mActive = false;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            final Button animatedButton = (Button) findViewById(R.id.animatedButton);
    
            Button button = (Button) findViewById(R.id.button);
            button.setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    ExpandCollapseAnimation animation = null;
                    if(mActive) {
                        animation = new ExpandCollapseAnimation(animatedButton, 1000, 1);
                        mActive = false;
                    } else {
                        animation = new ExpandCollapseAnimation(animatedButton, 1000, 0);
                        mActive = true;
                    }
                    animatedButton.startAnimation(animation);
                }
            });
        }
    }
    

    xml:

        <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
        <Button
            android:id="@+id/animatedButton"
            android:visibility="gone"
            android:layout_width="fill_parent"
            android:layout_height="50dp"
            android:text="@string/hello"/>
        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello" />
        <Button
            android:id="@+id/button"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello"/>
    </LinearLayout>
    

    Edit:

    Measure wrap_content height:

    So in order to get this to work for wrap_content I measured the height of the view before I start the animation and then use this measured height as the actual height. Bellow is code for measuring height of the view and set this as the new height (I assume the view uses screen width, change according to your own needs):

    /**
     * This methode can be used to calculate the height and set it for views with wrap_content as height. 
     * This should be done before ExpandCollapseAnimation is created.
     * @param activity
     * @param view
     */
    public static void setHeightForWrapContent(Activity activity, View view) {
        DisplayMetrics metrics = new DisplayMetrics();
        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
    
        int screenWidth = metrics.widthPixels;
    
        int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        int widthMeasureSpec = MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.EXACTLY);
    
        view.measure(widthMeasureSpec, heightMeasureSpec);
        int height = view.getMeasuredHeight();
        view.getLayoutParams().height = height;
    }
    
    0 讨论(0)
  • 2020-11-30 20:06

    Thank you Warpzit! That was a very helpful answer. In my case, I was only trying to animate views with height that was wrap_content. I tried triggs two-line suggestion, but it didn't work in my case. (I didn't spend much time pursuing why.) I ended up using a slightly modified form of Warpzit's ExpandCollapseAnimation with his static method to determine the height of the view

    In slightly more detail:

    1. I included his static method setHeightForWrapContent() in the ExpandCollapseAnimation class.
    2. I call the setHeightForWrapContent() in the ExpandCollapseAnimation constructor to properly determine the height of the view. To do this, I have to pass the activity in with the constructor.
    3. In the applyTransformation() method, when the view is finally reduced to zero height, I return the view's height back to wrap_content. If you don't do this, and change the content of the view later, when you expand it the view will expand to the height previously determined.

    The code is here:

    public class ExpandCollapseAnimation extends Animation {
        private View mAnimatedView;
        private int mEndHeight;
        private int mType;
    
        public ExpandCollapseAnimation(View view, int duration, int type, Activity activity) {
            setDuration(duration);
            mAnimatedView = view;
    
            setHeightForWrapContent(activity, view);
    
            mEndHeight = mAnimatedView.getLayoutParams().height;
    
            mType = type;
            if(mType == 0) {
                mAnimatedView.getLayoutParams().height = 0;
                mAnimatedView.setVisibility(View.VISIBLE);
            }
        }
    
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            if (interpolatedTime < 1.0f) {
                if(mType == 0) {
                    mAnimatedView.getLayoutParams().height = (int) (mEndHeight * interpolatedTime);
                } else {
                    mAnimatedView.getLayoutParams().height = mEndHeight - (int) (mEndHeight * interpolatedTime);
                }
                mAnimatedView.requestLayout();
            } else {
                if(mType == 0) {
                    mAnimatedView.getLayoutParams().height = mEndHeight;
                    mAnimatedView.requestLayout();
                } else {
                    mAnimatedView.getLayoutParams().height = 0;
                    mAnimatedView.setVisibility(View.GONE);
                    mAnimatedView.requestLayout();
                    mAnimatedView.getLayoutParams().height = LayoutParams.WRAP_CONTENT;     // Return to wrap
                }
            }
        }
    
        public static void setHeightForWrapContent(Activity activity, View view) {
            DisplayMetrics metrics = new DisplayMetrics();
            activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
    
            int screenWidth = metrics.widthPixels;
    
            int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
            int widthMeasureSpec = MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.EXACTLY);
    
            view.measure(widthMeasureSpec, heightMeasureSpec);
            int height = view.getMeasuredHeight();
            view.getLayoutParams().height = height;
        }
    }
    

    Thank you again, Warpzit!

    0 讨论(0)
提交回复
热议问题