content: package com.rsen.github.easyandroidanimations;
  
  import android.animation.Animator;
  import android.animation.AnimatorListenerAdapter;
  import android.animation.AnimatorSet;
  import android.animation.ObjectAnimator;
  import android.animation.TimeInterpolator;
  import android.graphics.Point;
  import android.view.View;
  import android.view.ViewGroup;
  import android.view.animation.AccelerateDecelerateInterpolator;
  
  import java.util.ArrayList;
  import java.util.List;
  
  /**
   * This animation translates the view within its parent view and according to
   * the ArrayList<Point> provided by the user. The values of X and Y in each
   * Point must be in the range of 0-100. Note: The status bar and action bar are
   * not taken into consideration for the translation.
   * 
   * @author SiYao
   * 
   */
  public class PathAnimation extends Animation implements Combinable {
  
  	public static final int ANCHOR_CENTER = 0, ANCHOR_TOP_LEFT = 1,
  			ANCHOR_TOP_RIGHT = 2, ANCHOR_BOTTOM_LEFT = 3,
  			ANCHOR_BOTTOM_RIGHT = 4;
  
  	ArrayList<Point> points;
  	int anchorPoint;
  	TimeInterpolator interpolator;
  	long duration;
  	AnimationListener listener;
  
  	/**
  	 * This animation translates the view within its parent view and according
  	 * to the ArrayList<Point> provided by the user. The values of X and Y in
  	 * each Point must be in the range of 0-100. Note: The status bar and action
  	 * bar are not taken into consideration for the translation.
  	 * 
  	 * @param view
  	 *            The view to be animated.
  	 */
  	public PathAnimation(View view) {
  		this.view = view;
  		points = null;
  		anchorPoint = ANCHOR_CENTER;
  		interpolator = new AccelerateDecelerateInterpolator();
  		duration = DURATION_LONG;
  		listener = null;
  	}
  
  	@Override
  	public void animate() {
  		getAnimatorSet().start();
  	}
  
  	@Override
  	public AnimatorSet getAnimatorSet() {
  		ViewGroup parentView = (ViewGroup) view.getParent(), rootView = (ViewGroup) view
  				.getRootView();
  		while (!parentView.equals(rootView)) {
  			parentView.setClipChildren(false);
  			parentView = (ViewGroup) parentView.getParent();
  		}
  		rootView.setClipChildren(false);
  
  		AnimatorSet pathSet = new AnimatorSet();
  		int numOfPoints = points.size();
  		AnimatorSet[] pathAnimSetArray = new AnimatorSet[numOfPoints];
  		List<Animator> pathAnimList = new ArrayList<Animator>();
  
  		parentView = (ViewGroup) view.getParent();
  		int parentWidth = parentView.getWidth(), parentHeight = parentView
  				.getHeight(), viewWidth = view.getWidth(), viewHeight = view
  				.getHeight();
  		float posX, posY;
  		for (int i = 0; i < numOfPoints; i++) {
  			posX = (points.get(i).x / 100f * parentWidth);
  			posY = (points.get(i).y / 100f * parentHeight);
  
  			switch (anchorPoint) {
  			case ANCHOR_CENTER:
  				posX = posX - viewWidth / 2;
  				posY = posY - viewHeight / 2;
  				break;
  			case ANCHOR_TOP_RIGHT:
  				posX -= viewWidth;
  				break;
  			case ANCHOR_BOTTOM_LEFT:
  				posY -= viewHeight;
  				break;
  			case ANCHOR_BOTTOM_RIGHT:
  				posX = posX - viewWidth;
  				posY = posY - viewHeight;
  				break;
  			default:
  				break;
  			}
  			pathAnimSetArray[i] = new AnimatorSet();
  			pathAnimSetArray[i].playTogether(
  					ObjectAnimator.ofFloat(view, View.X, posX),
  					ObjectAnimator.ofFloat(view, View.Y, posY));
  			pathAnimList.add(pathAnimSetArray[i]);
  		}
  
  		pathSet.playSequentially(pathAnimList);
  		pathSet.setInterpolator(interpolator);
  		pathSet.setDuration(duration / numOfPoints);
  		pathSet.addListener(new AnimatorListenerAdapter() {
  
  			@Override
  			public void onAnimationEnd(Animator animation) {
  				if (getListener() != null) {
  					getListener().onAnimationEnd(PathAnimation.this);
  				}
  			}
  		});
  		return pathSet;
  	}
  
  	/**
  	 * @return The ArrayList<Point> for the view to translate to.
  	 * @see java.util.ArrayList
  	 */
  	public ArrayList<Point> getPoints() {
  		return points;
  	}
  
  	/**
  	 * @param points
  	 *            The ArrayList<Point> to set for the view to translate to.
  	 * @return This object, allowing calls to methods in this class to be
  	 *         chained.
  	 * @see java.util.ArrayList
  	 */
  	public PathAnimation setPoints(ArrayList<Point> points) {
  		this.points = points;
  		return this;
  	}
  
  	/**
  	 * The available anchor points at which to translate the view are
  	 * <code>ANCHOR_CENTER</code>, <code>ANCHOR_TOP_LEFT</code>,
  	 * <code>ANCHOR_TOP_RIGHT</code>, <code>ANCHOR_BOTTOM_LEFT</code> and
  	 * <code>ANCHOR_BOTTOM_RIGHT</code>.
  	 * 
  	 * @return The anchor point at which to translate the view.
  	 */
  	public int getAnchorPoint() {
  		return anchorPoint;
  	}
  
  	/**
  	 * The available anchor points at which to translate the view are
  	 * <code>ANCHOR_CENTER</code>, <code>ANCHOR_TOP_LEFT</code>,
  	 * <code>ANCHOR_TOP_RIGHT</code>, <code>ANCHOR_BOTTOM_LEFT</code> and
  	 * <code>ANCHOR_BOTTOM_RIGHT</code>.
  	 * 
  	 * @param anchorPoint
  	 *            The anchor point to set at which to translate the view.
  	 * @return This object, allowing calls to methods in this class to be
  	 *         chained.
  	 */
  	public PathAnimation setAnchorPoint(int anchorPoint) {
  		this.anchorPoint = anchorPoint;
  		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 PathAnimation 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 PathAnimation 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 PathAnimation setListener(AnimationListener listener) {
  		this.listener = listener;
  		return this;
  	}
  }
  