package org.sugr.gearshift.ui.util; import android.content.res.Resources; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.view.ViewTreeObserver; import android.view.animation.Animation; import android.view.animation.Transformation; public class ExpandAnimation { private View target; public ExpandAnimation(View target) { this.target = target; } public void expand() { start(true); } public void collapse() { start(false); } private void start(final boolean expand) { if (expand) { target.setAlpha(0); target.setVisibility(View.VISIBLE); } else { target.setAlpha(1); target.setVisibility(View.GONE); } final ViewTreeObserver observer = target.getViewTreeObserver(); observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { observer.removeOnPreDrawListener(this); final int height = target.getHeight(); if (expand) { target.getLayoutParams().height = 0; target.requestLayout(); } else { target.setVisibility(View.VISIBLE); } final Animation a = new Animation() { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { if (interpolatedTime == 1) { if (expand) { target.animate().alpha(1); } else { target.setVisibility(View.GONE); } target.getLayoutParams().height = LayoutParams.WRAP_CONTENT; } else { if (expand) { target.getLayoutParams().height = (int) (height * interpolatedTime); } else { target.getLayoutParams().height = height - (int)(height * interpolatedTime); } } target.requestLayout(); } @Override public boolean willChangeBounds() { return true; } }; Resources resources = target.getContext().getResources(); int shortDuration = resources.getInteger(android.R.integer.config_shortAnimTime); int sizeDuration = (int) (height / resources.getDisplayMetrics().density); int duration = (int) Math.min(shortDuration, Math.max(sizeDuration, shortDuration * 1.5)); a.setDuration(duration); if (expand) { target.startAnimation(a); } else { target.animate().alpha(0).withEndAction(() -> target.startAnimation(a)); } return false; } }); } }