package com.marshalchen.common.uimodule.easyandroidanimations; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.TimeInterpolator; import android.graphics.Bitmap; import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.ImageView; import android.widget.LinearLayout; /** * This animation creates a bitmap of the view, divides them into customizable * number of X and Y parts and translates the parts away from the center of the * view to mimic an explosion. The number of parts can vary from 1x2 to 3x3. The * view is set to invisible and added back for reuse. * * @author SiYao * */ public class ExplodeAnimation extends Animation { public final static int MATRIX_1X2 = 12; public final static int MATRIX_1X3 = 13; public final static int MATRIX_2X1 = 21; public final static int MATRIX_2X2 = 22; public final static int MATRIX_2X3 = 23; public final static int MATRIX_3X1 = 31; public final static int MATRIX_3X2 = 32; public final static int MATRIX_3X3 = 33; private int xParts, yParts; ViewGroup parentView; int matrix; TimeInterpolator interpolator; long duration; AnimationListener listener; /** * This animation creates a bitmap of the view, divides them into * customizable number of X and Y parts and translates the parts away from * the center of the view to mimic an explosion. The number of parts can * vary from 1x2 to 3x3. The view is set to invisible and added back for * reuse. * * @param view * The view to be animated. */ public ExplodeAnimation(View view) { this.view = view; setExplodeMatrix(MATRIX_3X3); interpolator = new AccelerateDecelerateInterpolator(); duration = DURATION_LONG; listener = null; } @Override public void animate() { final LinearLayout explodeLayout = new LinearLayout(view.getContext()); LinearLayout[] layouts = new LinearLayout[yParts]; parentView = (ViewGroup) view.getParent(); explodeLayout.setLayoutParams(view.getLayoutParams()); explodeLayout.setOrientation(LinearLayout.VERTICAL); explodeLayout.setClipChildren(false); view.setDrawingCacheEnabled(true); Bitmap viewBmp = view.getDrawingCache(true); int totalParts = xParts * yParts, bmpWidth = viewBmp.getWidth() / xParts, bmpHeight = viewBmp.getHeight() / yParts, widthCount = 0, heightCount = 0, middleXPart = (xParts - 1) / 2; int[] translation = new int[2]; ImageView[] imageViews = new ImageView[totalParts]; for (int i = 0; i < totalParts; i++) { int translateX = 0, translateY = 0; if (i % xParts == 0) { if (i != 0) heightCount++; widthCount = 0; layouts[heightCount] = new LinearLayout(view.getContext()); layouts[heightCount].setClipChildren(false); translation = sideTranslation(heightCount, bmpWidth, bmpHeight, xParts, yParts); translateX = translation[0]; translateY = translation[1]; } else if (i % xParts == xParts - 1) { translation = sideTranslation(heightCount, -bmpWidth, bmpHeight, xParts, yParts); translateX = translation[0]; translateY = translation[1]; } else { if (widthCount == middleXPart) { if (heightCount == 0) { translateX = 0; if (yParts != 1) { translateY = -bmpHeight; } } else if (heightCount == yParts - 1) { translateX = 0; translateY = bmpHeight; } } } if (xParts == 1) { translation = sideTranslation(heightCount, 0, bmpHeight, xParts, yParts); translateX = translation[0]; translateY = translation[1]; } imageViews[i] = new ImageView(view.getContext()); imageViews[i] .setImageBitmap(Bitmap.createBitmap(viewBmp, bmpWidth * widthCount, bmpHeight * heightCount, bmpWidth, bmpHeight)); imageViews[i].animate().translationXBy(translateX) .translationYBy(translateY).alpha(0) .setInterpolator(interpolator).setDuration(duration); layouts[heightCount].addView(imageViews[i]); widthCount++; } for (int i = 0; i < yParts; i++) explodeLayout.addView(layouts[i]); final int positionView = parentView.indexOfChild(view); parentView.removeView(view); parentView.addView(explodeLayout, positionView); ViewGroup rootView = (ViewGroup) explodeLayout.getRootView(); while (!parentView.equals(rootView)) { parentView.setClipChildren(false); parentView = (ViewGroup) parentView.getParent(); } rootView.setClipChildren(false); imageViews[0].animate().setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { parentView = (ViewGroup) explodeLayout.getParent(); view.setLayoutParams(explodeLayout.getLayoutParams()); view.setVisibility(View.INVISIBLE); parentView.removeView(explodeLayout); parentView.addView(view, positionView); if (getListener() != null) { getListener().onAnimationEnd(ExplodeAnimation.this); } } }); } private int[] sideTranslation(int heightCount, int bmpWidth, int bmpHeight, int xParts, int yParts) { int[] translation = new int[2]; int middleYPart = (yParts - 1) / 2; if (heightCount == 0) { translation[0] = -bmpWidth; translation[1] = -bmpHeight; } else if (heightCount == yParts - 1) { translation[0] = -bmpWidth; translation[1] = bmpHeight; } if (yParts % 2 != 0) { if (heightCount == middleYPart) { translation[0] = -bmpWidth; translation[1] = 0; } } return translation; } /** * The available matrices are <code>MATRIX_1X2</code>, * <code>MATRIX_1X3</code>, <code>MATRIX_2X1</code>, <code>MATRIX_2X2</code> * , <code>MATRIX_2X3</code>, <code>MATRIX_3X1</code>, * <code>MATRIX_3X2</code> and <code>MATRIX_3X3</code>. * * @return The matrix that determines the number of X and Y parts. */ public int getExplodeMatrix() { return matrix; } /** * The available matrices are <code>MATRIX_1X2</code>, * <code>MATRIX_1X3</code>, <code>MATRIX_2X1</code>, <code>MATRIX_2X2</code> * , <code>MATRIX_2X3</code>, <code>MATRIX_3X1</code>, * <code>MATRIX_3X2</code> and <code>MATRIX_3X3</code>. * * @param matrix * The matrix that determines the number of X and Y parts to set. * @return This object, allowing calls to methods in this class to be * chained. */ public ExplodeAnimation setExplodeMatrix(int matrix) { this.matrix = matrix; xParts = matrix / 10; yParts = matrix % 10; return this; } /** * @return The interpolator of the entire animation. */ public TimeInterpolator getInterpolator() { return interpolator; } /** * @param interpolator * The interpolator of the entire animation to set. */ public ExplodeAnimation setInterpolator(TimeInterpolator interpolator) { this.interpolator = interpolator; return this; } /** * @return The duration of the entire animation. */ public long getDuration() { return duration; } /** * @param duration * The duration of the entire animation to set. * @return This object, allowing calls to methods in this class to be * chained. */ public ExplodeAnimation setDuration(long duration) { this.duration = duration; return this; } /** * @return The listener for the end of the animation. */ public AnimationListener getListener() { return listener; } /** * * @param listener * The listener to set for the end of the animation. * @return This object, allowing calls to methods in this class to be * chained. */ public ExplodeAnimation setListener(AnimationListener listener) { this.listener = listener; return this; } }