点击图中的星星开始翻转
源码:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.Transformation;
import android.widget.ImageView;
import fr.castorflex.android.flipimageview.R;
/**
* Created with IntelliJ IDEA. User: castorflex Date: 30/12/12 Time: 16:25
*/
public class FlipImageView extends ImageView implements View.OnClickListener,
Animation.AnimationListener {
private static final int FLAG_ROTATION_X = 1 << 0;
private static final int FLAG_ROTATION_Y = 1 << 1;
private static final int FLAG_ROTATION_Z = 1 << 2;
private static final Interpolator fDefaultInterpolator = new DecelerateInterpolator();
private static int sDefaultDuration;
private static int sDefaultRotations;
private static boolean sDefaultAnimated;
private static boolean sDefaultFlipped;
public interface OnFlipListener {
public void onClick(boolean flipped);
public void onFlipStart();
public void onFlipEnd();
}
private OnFlipListener mListener;
private boolean mIsFlipped;
private boolean mIsDefaultAnimated;
private Drawable mDrawable;
private Drawable mFlippedDrawable;
private FlipAnimator mAnimation;
private boolean mIsRotationXEnabled;
private boolean mIsRotationYEnabled;
private boolean mIsRotationZEnabled;
public FlipImageView(Context context) {
super(context);
init(context, null, 0);
}
public FlipImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public FlipImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
sDefaultDuration = context.getResources().getInteger(R.integer.default_fiv_duration);
sDefaultRotations = context.getResources().getInteger(R.integer.default_fiv_rotations);
sDefaultAnimated = context.getResources().getBoolean(R.bool.default_fiv_isAnimated);
sDefaultFlipped = context.getResources().getBoolean(R.bool.default_fiv_isFlipped);
TypedArray a = context
.obtainStyledAttributes(attrs, R.styleable.FlipImageView, defStyle, 0);
mIsDefaultAnimated = a.getBoolean(R.styleable.FlipImageView_isAnimated, sDefaultAnimated);
mIsFlipped = a.getBoolean(R.styleable.FlipImageView_isFlipped, sDefaultFlipped);
mFlippedDrawable = a.getDrawable(R.styleable.FlipImageView_flipDrawable);
int duration = a.getInt(R.styleable.FlipImageView_flipDuration, sDefaultDuration);
int interpolatorResId = a.getResourceId(R.styleable.FlipImageView_flipInterpolator, 0);
Interpolator interpolator = interpolatorResId > 0 ? AnimationUtils
.loadInterpolator(context, interpolatorResId) : fDefaultInterpolator;
int rotations = a.getInteger(R.styleable.FlipImageView_flipRotations, sDefaultRotations);
mIsRotationXEnabled = (rotations & FLAG_ROTATION_X) != 0;
mIsRotationYEnabled = (rotations & FLAG_ROTATION_Y) != 0;
mIsRotationZEnabled = (rotations & FLAG_ROTATION_Z) != 0;
mDrawable = getDrawable();
mAnimation = new FlipAnimator();
mAnimation.setAnimationListener(this);
mAnimation.setInterpolator(interpolator);
mAnimation.setDuration(duration);
setOnClickListener(this);
setImageDrawable(mIsFlipped ? mFlippedDrawable : mDrawable);
a.recycle();
}
public boolean isRotationXEnabled() {
return mIsRotationXEnabled;
}
public void setRotationXEnabled(boolean enabled) {
mIsRotationXEnabled = enabled;
}
public boolean isRotationYEnabled() {
return mIsRotationYEnabled;
}
public void setRotationYEnabled(boolean enabled) {
mIsRotationYEnabled = enabled;
}
public boolean isRotationZEnabled() {
return mIsRotationZEnabled;
}
public void setRotationZEnabled(boolean enabled) {
mIsRotationZEnabled = enabled;
}
public FlipAnimator getFlipAnimation() {
return mAnimation;
}
public void setInterpolator(Interpolator interpolator) {
mAnimation.setInterpolator(interpolator);
}
public void setDuration(int duration) {
mAnimation.setDuration(duration);
}
public boolean isFlipped() {
return mIsFlipped;
}
public boolean isAnimated() {
return mIsDefaultAnimated;
}
public void setAnimated(boolean animated) {
mIsDefaultAnimated = animated;
}
public void setFlipped(boolean flipped) {
setFlipped(flipped, mIsDefaultAnimated);
}
public void setFlipped(boolean flipped, boolean animated) {
if (flipped != mIsFlipped) {
toggleFlip(animated);
}
}
public void toggleFlip() {
toggleFlip(mIsDefaultAnimated);
}
public void toggleFlip(boolean animated) {
if (animated) {
mAnimation.setToDrawable(mIsFlipped ? mDrawable : mFlippedDrawable);
startAnimation(mAnimation);
} else {
setImageDrawable(mIsFlipped ? mDrawable : mFlippedDrawable);
}
mIsFlipped = !mIsFlipped;
}
public void setOnFlipListener(OnFlipListener listener) {
mListener = listener;
}
@Override
public void onClick(View v) {
toggleFlip();
if (mListener != null) {
mListener.onClick(mIsFlipped);
}
}
@Override
public void onAnimationStart(Animation animation) {
if (mListener != null) {
mListener.onFlipStart();
}
}
@Override
public void onAnimationEnd(Animation animation) {
if (mListener != null) {
mListener.onFlipEnd();
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
/**
* Animation part All credits goes to coomar
*/
public class FlipAnimator extends Animation {
private Camera camera;
private Drawable toDrawable;
private float centerX;
private float centerY;
private boolean forward = true;
private boolean visibilitySwapped;
public void setToDrawable(Drawable to) {
toDrawable = to;
visibilitySwapped = false;
}
public FlipAnimator() {
setFillAfter(true);
}
@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);
// 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) {
degrees -= 180.f;
if (!visibilitySwapped) {
setImageDrawable(toDrawable);
visibilitySwapped = true;
}
}
if (forward) {
degrees = -degrees;
}
final Matrix matrix = t.getMatrix();
camera.save();
camera.translate(0.0f, 0.0f, (float) (150.0 * Math.sin(radians)));
camera.rotateX(mIsRotationXEnabled ? degrees : 0);
camera.rotateY(mIsRotationYEnabled ? degrees : 0);
camera.rotateZ(mIsRotationZEnabled ? degrees : 0);
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
}
}
使用方法:
import android.app.Activity;
import android.os.Bundle;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.BounceInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.TextView;
import fr.castorflex.android.flipimageview.R;
import fr.castorflex.android.flipimageview.library.FlipImageView;
public class SampleActivity extends Activity implements FlipImageView.OnFlipListener,
SeekBar.OnSeekBarChangeListener {
private static final String[] fData = new String[]{
"Decelerate",
"Accelerate",
"AccelerateDecelerate",
"Bounce",
"Overshoot",
"AnticipateOvershoot"
};
private static final Interpolator[] fInterpolators = new Interpolator[]{
new DecelerateInterpolator(),
new AccelerateInterpolator(),
new AccelerateDecelerateInterpolator(),
new BounceInterpolator(),
new OvershootInterpolator(),
new AnticipateOvershootInterpolator()
};
private SeekBar mSeekBar;
private Spinner mSpinner;
private TextView mTextViewDuration;
private FlipImageView mFlipImageView;
private CheckBox mCheckBoxX;
private CheckBox mCheckBoxY;
private CheckBox mCheckBoxZ;
private TextView mTextViewAnimationListener;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTextViewAnimationListener = (TextView) findViewById(R.id.textview);
mFlipImageView = (FlipImageView) findViewById(R.id.imageview);
mSpinner = (Spinner) findViewById(R.id.spinner);
mTextViewDuration = (TextView) findViewById(R.id.textview_duration);
mSeekBar = (SeekBar) findViewById(R.id.seekbar);
mCheckBoxX = (CheckBox) findViewById(R.id.checkedtextview_x);
mCheckBoxY = (CheckBox) findViewById(R.id.checkedtextview_y);
mCheckBoxZ = (CheckBox) findViewById(R.id.checkedtextview_z);
mSpinner.setAdapter(
new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, fData));
mSeekBar.setOnSeekBarChangeListener(this);
mFlipImageView.setOnFlipListener(this);
}
/////////////////////FLIP IMAGE VIEW///////////////////
@Override
public void onClick(boolean flipped) {
mFlipImageView.setInterpolator(fInterpolators[mSpinner.getSelectedItemPosition()]);
mFlipImageView.setDuration(mSeekBar.getProgress());
mFlipImageView.setRotationXEnabled(mCheckBoxX.isChecked());
mFlipImageView.setRotationYEnabled(mCheckBoxY.isChecked());
mFlipImageView.setRotationZEnabled(mCheckBoxZ.isChecked());
}
@Override
public void onFlipStart() {
mTextViewAnimationListener.setText("OnFlipStart");
}
@Override
public void onFlipEnd() {
mTextViewAnimationListener.setText("OnFlipEnd");
}
////////////////////////SEEK BAR/////////////////////////
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
mTextViewDuration.setText("" + progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}