Android: add view with expand animation (without blinking)

11,614

This might be a little simpler:

public void expand(final View view) {
    view.getLayoutParams().height = 0;

    Animation a = new Animation() {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t)
        {
            view.getLayoutParams().height = (int)(mTargetHeight * interpolatedTime);
            view.requestLayout();
        }

        @Override
        public boolean willChangeBounds() {
            return true;
        }
    };

    a.setDuration(1000);
    view.startAnimation(a);
}
Share:
11,614
Ferran Maylinch
Author by

Ferran Maylinch

Developer at Yandex, and sometimes a teacher.

Updated on June 15, 2022

Comments

  • Ferran Maylinch
    Ferran Maylinch almost 2 years

    I want to add a view to a view group using an expanding animation, so the added view starts very small and takes more and more space until it reaches its full size (probably moving other views in the process).

    After trying different approaches I came up with the solution below. Vote if it helps you or please post a better alternative. I am sure there must be an easier way to do this.

    For more information see posts like this one and this one.

    Here's how I add the view and start the animation:

    // Trick: set height to 1 so the view doesn't take its full size at the beginning.
    // (0 doesn't work, I don't know why)
    container.addView(view, LayoutParams.MATCH_PARENT, 1);
    Animation expansion = createExpansion(view);
    expansion.setDuration(200);
    view.startAnimation(expansion);
    

    The createExpansion() method:

    public static Animation createExpansion(View view) {
    
        return new SizedHeightScaleAnimation(view, 0, 1,
                Animation.RELATIVE_TO_SELF, 0f,
                Animation.RELATIVE_TO_SELF, 0f);
    }
    

    And finally the SizedHeightScaleAnimation animation class:

    /**
     * Like {@link ScaleAnimation} for height scaling that also resizes the view accordingly,
     * so it takes the right amount of space while scaling.
     */
    public class SizedHeightScaleAnimation extends ScaleAnimation {
    
        private float fromHeight;
        private float toHeight;
        private View viewToScale;
    
        public SizedHeightScaleAnimation(View viewToScale, float fromY, float toY) {
            super(1, 1, fromY, toY);
            init(viewToScale, fromY, toY);
        }
    
        public SizedHeightScaleAnimation(View viewToScale, float fromY, float toY, float pivotX, float pivotY) {
            super(1, 1, fromY, toY, pivotX, pivotY);
            init(viewToScale, fromY, toY);
        }
    
        public SizedHeightScaleAnimation(View viewToScale, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {
            super(1, 1, fromY, toY, pivotXType, pivotXValue, pivotYType, pivotYValue);
            init(viewToScale, fromY, toY);
        }
    
        private void init(View viewToScale, float fromY, float toY) {
    
            this.viewToScale = viewToScale;
            viewToScale.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
            fromHeight = viewToScale.getMeasuredHeight() * fromY;
            toHeight = viewToScale.getMeasuredHeight() * toY;
        }
    
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
    
            final int newHeight = (int) (fromHeight * (1 - interpolatedTime) + toHeight * interpolatedTime);
    
            viewToScale.getLayoutParams().height = newHeight;
            viewToScale.requestLayout();
        }
    }
    

    By the way, you can create the collapse effect this way:

    public static Animation createCollapse(View view) {
    
        return new SizedHeightScaleAnimation(view, 1, 0,
                Animation.RELATIVE_TO_SELF, 0f,
                Animation.RELATIVE_TO_SELF, 0f);
    }
    

    When you use it you'll probably want to remove the view from its parent when the animation is done:

    Animation collapse = createCollapse(view);
    collapse.setDuration(200);
    
    collapse.setAnimationListener(new AnimationListener() {
        @Override
        public void onAnimationEnd(Animation animation) {
            final ViewGroup parent = (ViewGroup) view.getParent();
            parent.removeView(view);
        }
    
        ... other overrides ...
    });
    
    view.startAnimation(collapse);