Java tutorial
//package com.java2s; //License from project: Open Source License import android.annotation.TargetApi; import android.app.Activity; import android.graphics.Rect; import android.os.Build; import android.os.Handler; import android.os.Looper; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewTreeObserver; import android.view.animation.Animation; import android.view.animation.Transformation; public class Main { private static final int ANIMATION_DURATION = 300; public static void expand(final View view, final View parentView, final ViewGroup rootContainer, final int targtetHeight) { if (view == null || parentView == null || rootContainer == null) { return; } view.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); expandInner(view, parentView, rootContainer, targtetHeight); } public static void expand(final View view, final ViewGroup parentView) { expand(view, parentView, parentView); } public static void expand(final View view, final View parentView, final ViewGroup rootContainer) { if (view == null || parentView == null || rootContainer == null) { return; } view.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); int targetHeight = view.getMeasuredHeight(); expandInner(view, parentView, rootContainer, targetHeight); } private static void expandInner(final View view, final View parentView, final ViewGroup rootContainer, final int targtetHeight) { setHeight(view, 0); view.setVisibility(View.VISIBLE); final Animation animation = new Animation() { private final Rect rect = new Rect(); private final Rect parentVisibleRect = new Rect(); ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener; private final Runnable checkViewRunnable = new Runnable() { @Override public void run() { checkForViewInsideVisibleArea(); } }; @Override protected void applyTransformation(float interpolatedTime, Transformation t) { int neededHeight = interpolatedTime == 1 ? LayoutParams.WRAP_CONTENT : (int) (targtetHeight * interpolatedTime); setHeight(view, neededHeight); final ViewTreeObserver viewTreeObserver = view.getViewTreeObserver(); if (globalLayoutListener == null) { globalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (globalLayoutListener == null) { removeGlobalLayoutListener(viewTreeObserver, this); } checkForViewInsideVisibleArea(); } }; viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener); } if (globalLayoutListener != null && interpolatedTime == 1) { runInUIThread(checkViewRunnable); globalLayoutListener = null; } view.requestLayout(); } @Override public boolean willChangeBounds() { return true; } private void checkForViewInsideVisibleArea() { if (rootContainer.indexOfChild(parentView) == -1) { return; } parentVisibleRect.left = 0; parentVisibleRect.top = 0; parentVisibleRect.right = parentView.getWidth(); parentVisibleRect.bottom = parentView.getHeight(); rootContainer.offsetDescendantRectToMyCoords(parentView, parentVisibleRect); if (parentVisibleRect.top < 0 || parentVisibleRect.bottom > rootContainer.getHeight()) { rect.left = parentView.getLeft(); rect.top = parentView.getTop(); rect.right = parentView.getRight(); rect.bottom = parentView.getBottom(); parentView.requestRectangleOnScreen(rect, true); } } }; animation.setDuration(ANIMATION_DURATION); view.startAnimation(animation); } public static void setHeight(final View view, final int height) { if (view != null) { final ViewGroup.LayoutParams params = view.getLayoutParams(); // noinspection ConstantConditions params.height = height; view.setLayoutParams(params); } } public static void setHeight(final View root, final int viewId, final int height) { if (root != null) { setHeight(root.findViewById(viewId), height); } } public static void setHeight(final Activity root, final int viewId, final int height) { if (root != null) { setHeight(root.findViewById(viewId), height); } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public static void removeGlobalLayoutListener(final ViewTreeObserver viewTreeObserver, final ViewTreeObserver.OnGlobalLayoutListener listener) { if (viewTreeObserver == null) { return; } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { viewTreeObserver.removeGlobalOnLayoutListener(listener); } else { viewTreeObserver.removeOnGlobalLayoutListener(listener); } } public static void removeGlobalLayoutListener(final View view, final ViewTreeObserver.OnGlobalLayoutListener listener) { if (view == null) { return; } removeGlobalLayoutListener(view.getViewTreeObserver(), listener); } public static Handler runInUIThread(final Runnable runnable) { return runInUIThread(runnable, false); } public static Handler runInUIThread(final Runnable runnable, boolean runImmediatelyIfPossible) { if (runnable == null) { return null; } final Handler handler; Looper mainLooper = Looper.getMainLooper(); if (runImmediatelyIfPossible && (Thread.currentThread() == mainLooper.getThread())) { handler = null; runnable.run(); } else { handler = new Handler(mainLooper); handler.post(runnable); } return handler; } }