/*
* Created by Storm Zhang, Mar 31, 2014.
*/
package com.youzi.zhidu.lib;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.Transformation;
import android.widget.FrameLayout;
public class FlipLayout extends FrameLayout implements View.OnClickListener,
Animation.AnimationListener {
private static final int DURATION = 800;
private static final Interpolator fDefaultInterpolator = new DecelerateInterpolator();
private OnFlipListener mListener;
private FlipAnimator mAnimation;
private boolean mIsFlipped;
private boolean mIsRotationReversed;
private View mFrontView, mBackView;
public FlipLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public FlipLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public FlipLayout(Context context) {
super(context);
init();
}
private void init() {
mAnimation = new FlipAnimator();
mAnimation.setAnimationListener(this);
mAnimation.setInterpolator(fDefaultInterpolator);
mAnimation.setDuration(DURATION);
setOnClickListener(this);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (getChildCount() > 2) {
throw new IllegalStateException("FlipLayout can host only two direct children");
}
mFrontView = getChildAt(0);
mBackView = getChildAt(1);
}
private void toggleView() {
if (mFrontView == null || mBackView == null) {
return;
}
if (mIsFlipped) {
mFrontView.setVisibility(View.VISIBLE);
mBackView.setVisibility(View.GONE);
} else {
mFrontView.setVisibility(View.GONE);
mBackView.setVisibility(View.VISIBLE);
}
mIsFlipped = !mIsFlipped;
}
public void setOnFlipListener(OnFlipListener listener) {
mListener = listener;
}
public void reset() {
mIsFlipped = false;
mIsRotationReversed = false;
mFrontView.setVisibility(View.VISIBLE);
mBackView.setVisibility(View.GONE);
}
@Override
public void onClick(View v) {
mAnimation.setVisibilitySwapped();
startAnimation(mAnimation);
if (mListener != null) {
mListener.onClick(this);
}
}
public interface OnFlipListener {
public void onClick(FlipLayout view);
public void onFlipStart(FlipLayout view);
public void onFlipEnd(FlipLayout view);
}
public class FlipAnimator extends Animation {
private Camera camera;
private float centerX;
private float centerY;
private boolean visibilitySwapped;
public FlipAnimator() {
setFillAfter(true);
}
public void setVisibilitySwapped() {
visibilitySwapped = false;
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
camera = new Camera();
this.centerX = width / 2;
this.centerY = height / 2;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
// Angle around the y-axis of the rotation at the given time. It is
// calculated both in radians and in the equivalent degrees.
final double radians = Math.PI * interpolatedTime;
float degrees = (float) (180.0 * radians / Math.PI);
if (mIsRotationReversed) {
degrees = -degrees;
}
// Once we reach the midpoint in the animation, we need to hide the
// source view and show the destination view. We also need to change
// the angle by 180 degrees so that the destination does not come in
// flipped around. This is the main problem with SDK sample, it does
// not
// do this.
if (interpolatedTime >= 0.5f) {
if (mIsRotationReversed) {
degrees += 180.f;
} else {
degrees -= 180.f;
}
if (!visibilitySwapped) {
toggleView();
visibilitySwapped = true;
}
}
final Matrix matrix = t.getMatrix();
camera.save();
camera.translate(0.0f, 0.0f, (float) (150.0 * Math.sin(radians)));
camera.rotateX(0);
camera.rotateY(degrees);
camera.rotateZ(0);
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
}
@Override
public void onAnimationStart(Animation animation) {
if (mListener != null) {
mListener.onFlipStart(this);
}
}
@Override
public void onAnimationEnd(Animation animation) {
if (mListener != null) {
mListener.onFlipEnd(this);
}
mIsRotationReversed = !mIsRotationReversed;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
}