package external.otherview;
import com.aiyou.BaseActivity;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
/**
* Utility class to create a split activity animation
*
* @author Udi Cohen (@udinic)
*/
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public class ActivitySplitAnimationUtil {
public static Bitmap mBitmap = null;
private static boolean isPlaying = false;
private static int[] mLoc1;
private static int[] mLoc2;
private static ImageView mLeftImage;
private static ImageView mRightImage;
private static AnimatorSet mSetAnim;
/**
* Start a new Activity with a Split animation
*
* @param currActivity The current Activity
* @param intent The Intent needed tot start the new Activity
* @param splitXPercent The X percentage where we want to split the Activity
* on the animation. -1 will split the Activity equally
*/
public static void startActivity(Activity currActivity, Intent intent,
double splitXPercent) {
// Preparing the bitmaps that we need to show
prepare(currActivity, splitXPercent);
currActivity.startActivity(intent);
currActivity.overridePendingTransition(0, 0);
}
/**
* Start a new Activity with a Split animation right in the middle of the
* Activity
*
* @param currActivity The current Activity
* @param intent The Intent needed tot start the new Activity
*/
public static void startActivity(Activity currActivity, Intent intent) {
startActivity(currActivity, intent, -1);
}
/**
* Preparing the graphics on the destination Activity. Should be called on
* the destination activity on Activity#onCreate() BEFORE setContentView()
*
* @param destActivity the destination Activity
*/
public static void prepareAnimation(final Activity destActivity) {
mLeftImage = createImageView(destActivity, mBitmap, mLoc1);
mRightImage = createImageView(destActivity, mBitmap, mLoc2);
}
/**
* 判断是否可以进行动画
*
* @return
*/
public static boolean canPlay() {
if (mBitmap == null) {
return false;
} else {
return true;
}
}
/**
* 关闭activity
*
* @param activity
*/
public static void finish(final BaseActivity activity) {
if (canPlay()) {
if (isPlaying) {
return;
}
// 中心关闭动画
ActivitySplitAnimationUtil.prepareAnimation(activity);
ActivitySplitAnimationUtil.animate(activity, 1000, false, true);
} else {
activity.scrollToFinishActivity();
}
}
/**
* Start the animation the reveals the destination Activity Should be called
* on the destination activity on Activity#onCreate() AFTER setContentView()
*
* @param destActivity the destination Activity
* @param duration The duration of the animation
* @param interpolator The interpulator to use for the animation. null for
* no interpulation.
*/
public static void animate(final Activity destActivity, final int duration,
final boolean flagopen, final boolean needCleanBmp, final TimeInterpolator interpolator) {
// Post this on the UI thread's message queue. It's needed for the items
// to be already measured
new Handler().post(new Runnable() {
@SuppressLint("NewApi")
@Override
public void run() {
mSetAnim = new AnimatorSet();
mLeftImage.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mRightImage.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mSetAnim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
isPlaying = true;
}
@Override
public void onAnimationEnd(Animator animation) {
isPlaying = false;
if (needCleanBmp) {
destActivity.finish();
destActivity.overridePendingTransition(0, 0);
clean(destActivity);
mBitmap = null;
} else {
clean(destActivity);
}
}
@Override
public void onAnimationCancel(Animator animation) {
isPlaying = false;
if (needCleanBmp) {
destActivity.finish();
destActivity.overridePendingTransition(0, 0);
clean(destActivity);
mBitmap = null;
} else {
clean(destActivity);
}
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
float from1 = 0, from2 = 0, to1 = 0, to2 = 0;
if (flagopen) {
from1 = 0;
from2 = 0;
to1 = mLeftImage.getWidth() * -1;
to2 = mRightImage.getWidth();
} else {
from1 = mLeftImage.getWidth() * -1;
from2 = mRightImage.getWidth();
to1 = 0;
to2 = 0;
}
// Animating the 2 parts away from each other
Animator anim1 = ObjectAnimator.ofFloat(mLeftImage,
"translationX", from1, to1);
Animator anim2 = ObjectAnimator.ofFloat(mRightImage,
"translationX", from2, to2);
if (interpolator != null) {
anim1.setInterpolator(interpolator);
anim2.setInterpolator(interpolator);
}
mSetAnim.setDuration(duration);
mSetAnim.playTogether(anim1, anim2);
mSetAnim.start();
}
});
}
/**
* Start the animation that reveals the destination Activity Should be
* called on the destination activity on Activity#onCreate() AFTER
* setContentView()
*
* @param destActivity the destination Activity
* @param duration The duration of the animation
*/
public static void animate(final Activity destActivity, final int duration) {
animate(destActivity, duration, true, false, new DecelerateInterpolator());
}
public static void animate(final Activity destActivity, final int duration,
final boolean flagopen, final boolean needCleanBmp) {
animate(destActivity, duration, flagopen, needCleanBmp, new DecelerateInterpolator());
}
/**
* Cancel an in progress animation
*/
public static void cancel() {
mBitmap = null;
if (mSetAnim != null)
mSetAnim.cancel();
}
public static void destroy() {
if (mBitmap != null && !mBitmap.isRecycled()) {
mBitmap.recycle();
}
cancel();
}
/**
* Clean stuff
*
* @param activity The Activity where the animation is occurring
*/
@SuppressLint("NewApi")
private static void clean(Activity activity) {
if (mLeftImage != null) {
mLeftImage.setLayerType(View.LAYER_TYPE_NONE, null);
try {
// If we use the regular removeView() we'll get a small UI
// glitch
activity.getWindowManager().removeViewImmediate(mRightImage);
} catch (Exception ignored) {
}
}
if (mRightImage != null) {
mRightImage.setLayerType(View.LAYER_TYPE_NONE, null);
try {
activity.getWindowManager().removeViewImmediate(mLeftImage);
} catch (Exception ignored) {
}
}
// mBitmap = null;
}
/**
* Preparing the graphics for the animation
*
* @param currActivity the current Activity from where we start the new one
* @param splitXPercent The Y percentage where we want to split the
* activity. -1 will split the activity equally
*/
private static void prepare(Activity currActivity, double splitXPercent) {
// Get the content of the activity and put in a bitmap
View root = currActivity.getWindow().getDecorView()
.findViewById(android.R.id.content);
root.setDrawingCacheEnabled(true);
mBitmap = root.getDrawingCache();
// If the split Y coordinate is -1 - We'll split the activity equally
splitXPercent = (splitXPercent != -1 ? splitXPercent : 0.5);
if (splitXPercent > 0.9)
splitXPercent = 0.9;
// throw new IllegalArgumentException("Split X coordinate ["
// + splitXPercent + "] exceeds the activity's height ["
// + mBitmap.getHeight() + "]");
int splitXCoor = (int) (mBitmap.getWidth() * splitXPercent);
// Set the location to put the 2 bitmaps on the destination activity
mLoc1 = new int[] {
0, splitXCoor, root.getLeft()
};
mLoc2 = new int[] {
splitXCoor, mBitmap.getWidth(), root.getLeft()
};
}
/**
* Creating the an image, containing one part of the animation on the
* destination activity
*
* @param destActivity The destination activity
* @param bmp The Bitmap of the part we want to add to the destination
* activity
* @param loc The location this part should be on the screen
* @return
*/
private static ImageView createImageView(Activity destActivity, Bitmap bmp,
int loc[]) {
MyImageView imageView = new MyImageView(destActivity);
imageView.setImageBitmap(bmp);
imageView.setImageOffsets(bmp.getHeight(), loc[0], loc[1]);
// 获取状态栏高度
Rect frame = new Rect();
destActivity.getWindow().getDecorView()
.getWindowVisibleDisplayFrame(frame);
WindowManager.LayoutParams windowParams = new WindowManager.LayoutParams();
windowParams.gravity = Gravity.START;
windowParams.x = loc[2] + loc[0];
windowParams.y = frame.bottom;
windowParams.height = bmp.getHeight();
windowParams.width = loc[1] - loc[0];
windowParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
windowParams.format = PixelFormat.TRANSLUCENT;
windowParams.windowAnimations = 0;
destActivity.getWindowManager().addView(imageView, windowParams);
return imageView;
}
/**
* MyImageView Extended ImageView that draws just part of an image, base on
* start/end position
*/
private static class MyImageView extends ImageView {
private Rect mSrcRect;
private Rect mDstRect;
private Paint mPaint;
public MyImageView(Context context) {
super(context);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
/**
* Setting the bitmap offests to control the visible area
*
* @param width The bitmap image
* @param bmp The start X position
* @param loc The end X position
* @return
*/
public void setImageOffsets(int height, int startX, int endX) {
mSrcRect = new Rect(startX, 0, endX, height);
mDstRect = new Rect(0, 0, endX - startX, height);
}
@Override
protected void onDraw(Canvas canvas) {
Bitmap bm = null;
Drawable drawable = getDrawable();
if (null != drawable && drawable instanceof BitmapDrawable) {
bm = ((BitmapDrawable) drawable).getBitmap();
}
if (null == bm) {
super.onDraw(canvas);
} else {
canvas.drawBitmap(bm, mSrcRect, mDstRect, mPaint);
}
}
}
}