Animation of height of LinearLayout container with ValueAnimator

span picture span · Aug 13, 2012 · Viewed 28.4k times · Source

I have a LinearLayout that I use as a container for some buttons and textview's that I would like to animate the height of to give an impression of the layout sliding down when the user presses a "show" button.

I have set the LinearLayout to layout_height="0dp" and visibility="gone" in my xml. I then wish to set it to be visible and whatever height is need to wrap the content. At the moment I'm having issues even animating it at all, nevermind the wrap content height.

Here's my method for animating:

private void toggle(final LinearLayout v) {
    v.setVisibility(View.VISIBLE);
    ValueAnimator va = ValueAnimator.ofInt(0, 300);
    va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        public void onAnimationUpdate(ValueAnimator animation) {
            Integer value = (Integer) animation.getAnimatedValue();
            v.getLayoutParams().height = value.intValue();
            v.invalidate();

        }
    });

    va.start();
}

Perhaps the problem is how I am setting the height of the LinearLayout? Or am I misunderstanding the function of the ValueAnimator? I've looked around at the blog post's by Chet Haase but they do not contain any specific height animation examples. Neither have I been able to find and good examples of how to work with animations of height using API's from 3.0+. Would love some help on this, thanks!

Answer

span picture span · Aug 13, 2012

Looking at this blog post: http://tech.chitgoks.com/2011/10/29/android-animation-to-expand-collapse-view-its-children/ I found that I shouldn't use view.invalidate() to have the layout redrawn. I should use view.requestLayout().

Thus the code becomes something like this:

ValueAnimator va = ValueAnimator.ofInt(0, height);
    va.setDuration(700);
    va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        public void onAnimationUpdate(ValueAnimator animation) {
            Integer value = (Integer) animation.getAnimatedValue();
            v.getLayoutParams().height = value.intValue();
            v.requestLayout();
        }
    });

I just wanted to add a note on how to get the height of the LinearLayout as well to make the animation dynamic. To get the height all the views need to be drawn first. Therfor we have to listen for an event that tells us that the drawing is done. This can be done from the onResume() method like this (note that in my xml I have declared the container to wrap_content for height and it is also visible, since I want to hide it from the start I do that efter measuring it):

@Override
    public void onResume() {
        super.onResume();
        final ViewTreeObserver vto = filterContainer.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                height = filterContainer.getHeight();
                filterContainer.setVisibility(View.GONE);
                filterContainer.getLayoutParams().height = 0;
                filterContainer.requestLayout();
                ViewTreeObserver obs = filterContainer.getViewTreeObserver();
                obs.removeGlobalOnLayoutListener(this);
            }
        });
    }