content: package com.rsen.github.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;
  	}
  
  }
  