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.view.View;
  import android.view.ViewGroup;
  import android.view.animation.AccelerateDecelerateInterpolator;
  
  /**
   * This animation causes the view to flip horizontally to reveal another
   * user-provided view at the back of the original view. On animation end, the
   * original view is restored to its original state and is set to
   * <code>View.INVISIBLE</code>.
   * 
   * @author SiYao
   * 
   */
  public class FlipHorizontalToAnimation extends Animation {
  
  	public static final int PIVOT_CENTER = 0, PIVOT_LEFT = 1, PIVOT_RIGHT = 2;
  
  	View flipToView;
  	int pivot, direction;
  	TimeInterpolator interpolator;
  	long duration;
  	AnimationListener listener;
  
  	/**
  	 * This animation causes the view to flip horizontally to reveal another
  	 * user-provided view at the back of the original view. On animation end,
  	 * the original view is restored to its original state and is set to
  	 * <code>View.INVISIBLE</code>.
  	 * 
  	 * @param view
  	 *            The view to be animated.
  	 */
  	public FlipHorizontalToAnimation(View view) {
  		this.view = view;
  		flipToView = null;
  		pivot = PIVOT_CENTER;
  		direction = DIRECTION_RIGHT;
  		interpolator = new AccelerateDecelerateInterpolator();
  		duration = DURATION_LONG;
  		listener = null;
  	}
  
  	@Override
  	public void animate() {
  		ViewGroup parentView = (ViewGroup) view.getParent(), rootView = (ViewGroup) view
  				.getRootView();
  
  		float pivotX, pivotY, flipAngle = 270f, viewWidth = view.getWidth(), viewHeight = view
  				.getHeight();
  		final float originalRotationY = view.getRotationY();
  		switch (pivot) {
  		case PIVOT_LEFT:
  			pivotX = 0f;
  			pivotY = viewHeight / 2;
  			break;
  		case PIVOT_RIGHT:
  			pivotX = viewWidth;
  			pivotY = viewHeight / 2;
  			break;
  		default:
  			pivotX = viewWidth / 2;
  			pivotY = viewHeight / 2;
  			flipAngle = 90f;
  			break;
  		}
  		view.setPivotX(pivotX);
  		view.setPivotY(pivotY);
  		flipToView.setLayoutParams(view.getLayoutParams());
  		flipToView.setLeft(view.getLeft());
  		flipToView.setTop(view.getTop());
  		flipToView.setPivotX(pivotX);
  		flipToView.setPivotY(pivotY);
  		flipToView.setVisibility(View.VISIBLE);
  
  		while (parentView != rootView) {
  			parentView.setClipChildren(false);
  			parentView = (ViewGroup) parentView.getParent();
  		}
  		rootView.setClipChildren(false);
  
  		AnimatorSet flipToAnim = new AnimatorSet();
  		if (direction == DIRECTION_RIGHT) {
  			flipToView.setRotationY(270f);
  			flipToAnim.playSequentially(ObjectAnimator.ofFloat(view,
  					View.ROTATION_Y, 0f, flipAngle), ObjectAnimator.ofFloat(
  					flipToView, View.ROTATION_Y, 270f, 360f));
  		} else {
  			flipToView.setRotationY(-270f);
  			flipToAnim.playSequentially(ObjectAnimator.ofFloat(view,
  					View.ROTATION_Y, 0f, -flipAngle), ObjectAnimator.ofFloat(
  					flipToView, View.ROTATION_Y, -270f, -360f));
  		}
  		flipToAnim.setInterpolator(interpolator);
  		flipToAnim.setDuration(duration / 2);
  		flipToAnim.addListener(new AnimatorListenerAdapter() {
  
  			@Override
  			public void onAnimationEnd(Animator animation) {
  				view.setVisibility(View.INVISIBLE);
  				view.setRotationY(originalRotationY);
  				if (getListener() != null) {
  					getListener()
  							.onAnimationEnd(FlipHorizontalToAnimation.this);
  				}
  			}
  		});
  		flipToAnim.start();
  	}
  
  	/**
  	 * @return The view to be revealed after flipping the original view.
  	 */
  	public View getFlipToView() {
  		return flipToView;
  	}
  
  	/**
  	 * @param flipToView
  	 *            The view to set to be revealed after flipping the original
  	 *            view.
  	 * @return This object, allowing calls to methods in this class to be
  	 *         chained.
  	 */
  	public FlipHorizontalToAnimation setFlipToView(View flipToView) {
  		this.flipToView = flipToView;
  		return this;
  	}
  
  	/**
  	 * The available pivot points to flip are <code>PIVOT_CENTER</code>,
  	 * <code>PIVOT_LEFT</code> and <code>PIVOT_RIGHT</code>.
  	 * 
  	 * @return The pivot point for flipping.
  	 */
  	public int getPivot() {
  		return pivot;
  	}
  
  	/**
  	 * The available pivot points to flip are <code>PIVOT_CENTER</code>,
  	 * <code>PIVOT_LEFT</code> and <code>PIVOT_RIGHT</code>.
  	 * 
  	 * @param pivot
  	 *            The pivot point to set for flipping.
  	 * @return This object, allowing calls to methods in this class to be
  	 *         chained.
  	 */
  	public FlipHorizontalToAnimation setPivot(int pivot) {
  		this.pivot = pivot;
  		return this;
  	}
  
  	/**
  	 * The available flip directions are <code>DIRECTION_LEFT</code> and
  	 * <code>DIRECTION_RIGHT</code>.
  	 * 
  	 * @return The direction of the flip.
  	 * @see Animation
  	 */
  	public int getDirection() {
  		return direction;
  	}
  
  	/**
  	 * The available flip directions are <code>DIRECTION_LEFT</code> and
  	 * <code>DIRECTION_RIGHT</code>.
  	 * 
  	 * @param direction
  	 *            The direction of the flip to set.
  	 * @return This object, allowing calls to methods in this class to be
  	 *         chained.
  	 * @see Animation
  	 */
  	public FlipHorizontalToAnimation setDirection(int direction) {
  		this.direction = direction;
  		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 FlipHorizontalToAnimation 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 FlipHorizontalToAnimation 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 FlipHorizontalToAnimation setListener(AnimationListener listener) {
  		this.listener = listener;
  		return this;
  	}
  
  }
  