少說話,上圖似忧。渣叛。。
看了效果圖不高興盯捌,就繞道了淳衙。。饺著。哈哈
2016-12-15 20_08_16.gif
2016-12-15 20_14_06.gif
利用Surfaceview實現(xiàn)位移動畫效果箫攀,可以根據(jù)具體需求,自己編寫位移動畫執(zhí)行的算法幼衰。比如靴跛,電商APP中加入購物車的動畫、特殊曲線的動畫等等渡嚣。
Github地址:https://github.com/qizhenghao/AnimationSurfaceView
以第一個拋物線的動畫為例:
在demoActivity中初始化動畫:
private void initParabolaAnimation() {
animationSurfaceView = (AnimationSurfaceView) findViewById(R.id.animation_surfaceView);
animationSurfaceView.setOnAnimationStausChangedListener(this);
// 設置起始Y軸高度和終止X軸位移
iAnimationStrategy = new ParabolaAnimationStrategy(animationSurfaceView, dp2px(320), dp2px(320));
animationSurfaceView.setStrategy(iAnimationStrategy);
animationSurfaceView.setIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
animationSurfaceView.startAnimation();
}
AnimationSurfaceView 繼承自 SurfaceView:
package com.bruce.open.animationsurfaceview.lib;
import android.content.Context;
import android.graphics.*;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
* @author zhenghao.qi
* @version 1.0
* @time 2015年11月09日15:24:15
*/
public class AnimationSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private static final String TAG = "AnimationSurfaceView";
private static final long REFRESH_INTERVAL_TIME = 15l;//每間隔15ms刷一幀
private SurfaceHolder mSurfaceHolder;
private Bitmap mBitmap; //動畫圖標
private IAnimationStrategy mIAnimationStrategy; //動畫執(zhí)行算法策略
private OnStausChangedListener mStausChangedListener; //動畫狀態(tài)改變監(jiān)聽事件
private int marginLeft;
private int marginTop;
private boolean isSurfaceDestoryed = true; //默認未創(chuàng)建梢睛,相當于Destory
private Thread mThread; //動畫刷新線程
public AnimationSurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public AnimationSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AnimationSurfaceView(Context context) {
super(context);
init();
}
//初始化
private void init() {
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
setZOrderOnTop(true);//設置畫布背景透明
mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
mThread = new Thread(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
isSurfaceDestoryed = false;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isSurfaceDestoryed = true;
if (mIAnimationStrategy != null)//如果surfaceView創(chuàng)建后,沒有執(zhí)行setStrategy,就被銷毀识椰,會空指針異常
mIAnimationStrategy.cancel();
}
//執(zhí)行
private void executeAnimationStrategy() {
Canvas canvas = null;
Paint tempPaint = new Paint();
tempPaint.setAntiAlias(true);
tempPaint.setColor(Color.TRANSPARENT);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.CYAN);
if (mStausChangedListener != null) {
mStausChangedListener.onAnimationStart(this);
}
mIAnimationStrategy.start();
while (mIAnimationStrategy.doing()) {
try {
mIAnimationStrategy.compute();
canvas = mSurfaceHolder.lockCanvas();
canvas.drawColor(Color.TRANSPARENT, android.graphics.PorterDuff.Mode.CLEAR);// 設置畫布的背景為透明
// 繪上新圖區(qū)域
float x = (float) mIAnimationStrategy.getX() + marginLeft;
float y = (float) mIAnimationStrategy.getY() + marginTop;
canvas.drawRect(x, y, x + mBitmap.getWidth(), y + mBitmap.getHeight(), tempPaint);
canvas.drawBitmap(mBitmap, x, y, paint);
mSurfaceHolder.unlockCanvasAndPost(canvas);
Thread.sleep(REFRESH_INTERVAL_TIME);
} catch (Exception e) {
e.printStackTrace();
}
}
// clear屏幕內(nèi)容
if (isSurfaceDestoryed == false) {// 如果直接按Home鍵回到桌面绝葡,這時候SurfaceView已經(jīng)被銷毀了,lockCanvas會返回為null腹鹉。
canvas = mSurfaceHolder.lockCanvas();
canvas.drawColor(Color.TRANSPARENT, android.graphics.PorterDuff.Mode.CLEAR);
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
if (mStausChangedListener != null) {
mStausChangedListener.onAnimationEnd(this);
}
}
/**
* 開始播放動畫
*/
public void startAnimation() {
if (mThread.getState() == Thread.State.NEW) {
mThread.start();
} else if (mThread.getState() == Thread.State.TERMINATED) {
mThread = new Thread(this);
mThread.start();
}
}
/**
* 是否正在播放動畫
*/
public boolean isShow() {
return mIAnimationStrategy.doing();
}
/**
* 結(jié)束動畫
*/
public void endAnimation() {
mIAnimationStrategy.cancel();
}
/**
* 設置要播放動畫的bitmap
*
* @param bitmap
*/
public void setIcon(Bitmap bitmap) {
this.mBitmap = bitmap;
}
/**
* 獲取要播放動畫的bitmap
*/
public Bitmap getIcon() {
return mBitmap;
}
/**
* 設置margin left 像素
*
* @param marginLeftPx
*/
public void setMarginLeft(int marginLeftPx) {
this.marginLeft = marginLeftPx;
}
/**
* 設置margin left 像素
*
* @param marginTopPx
*/
public void setMarginTop(int marginTopPx) {
this.marginTop = marginTopPx;
}
/**
* 設置動畫狀態(tài)改變監(jiān)聽器
*/
public void setOnAnimationStausChangedListener(OnStausChangedListener listener) {
this.mStausChangedListener = listener;
}
@Override
public void run() {
executeAnimationStrategy();
}
public interface OnStausChangedListener {
void onAnimationStart(AnimationSurfaceView view);
void onAnimationEnd(AnimationSurfaceView view);
}
/**
* 設置動畫執(zhí)行算法策略
*
* @param strategy
*/
public void setStrategy(IAnimationStrategy strategy) {
this.mIAnimationStrategy = strategy;
}
}
具體執(zhí)行的動畫算法策略:
package com.bruce.open.animationsurfaceview.strategies;
import android.util.Log;
import com.bruce.open.animationsurfaceview.lib.AnimationSurfaceView;
import com.bruce.open.animationsurfaceview.lib.IAnimationStrategy;
/**
* @author zhenghao.qi
* @version 2015年11月10日10:40:03
*/
public class ParabolaAnimationStrategy implements IAnimationStrategy {
/**
* 重力加速度值藏畅。
*/
private static final float GRAVITY = 400.78033f;
/**
* 與X軸碰撞后,重力勢能損失掉的百分比功咒。
*/
private static final float WASTAGE = 0.3f;
/**
* 起始下降高度墓赴。
*/
private int height;
/**
* 起始點到終點的X軸位移竞膳。
*/
private int width;
/**
* 水平位移速度。
*/
private double velocity;
/**
* X Y坐標诫硕。
*/
private double x, y;
/**
* 動畫開始時間坦辟。
*/
private long startTime;
/**
* 首階段下載的時間。 單位:毫秒章办。
*/
private double t1;
/**
* 第二階段上升與下載的時間锉走。 單位:毫秒。
*/
private double t2;
/**
* 動畫正在進行時值為true藕届,反之為false挪蹭。
*/
private boolean doing;
private AnimationSurfaceView animationSurfaceView;
public ParabolaAnimationStrategy(AnimationSurfaceView animationSurfaceView, int h, int w) {
this.animationSurfaceView = animationSurfaceView;
setParams(h, w);
}
public void start() {
startTime = System.currentTimeMillis();
doing = true;
}
/**
* 設置起始下落的高度及水平位移寬度;以此計算水平初速度休偶、計算小球下落的第一階段及第二階段上升耗時梁厉。
*/
private void setParams(int h, int w) {
height = h;
width = w;
t1 = Math.sqrt(2 * height * 1.0d / GRAVITY);
t2 = Math.sqrt((1 - WASTAGE) * 2 * height * 1.0d / GRAVITY);
velocity = width * 1.0d / (t1 + 2 * t2);
Log.d("Bruce1", "t1=" + t1 + " t2=" + t2);
}
/**
* 根據(jù)當前時間計算小球的X/Y坐標。
*/
public void compute() {
double used = (System.currentTimeMillis() - startTime) * 1.0d / 1000;
x = velocity * used;
if (0 <= used && used < t1) {
y = height - 0.5d * GRAVITY * used * used;
} else if (t1 <= used && used < (t1 + t2)) {
double tmp = t1 + t2 - used;
y = (1 - WASTAGE) * height - 0.5d * GRAVITY * tmp * tmp;
} else if ((t1 + t2) <= used && used < (t1 + 2 * t2)) {
double tmp = used - t1 - t2;
y = (1 - WASTAGE) * height - 0.5d * GRAVITY * tmp * tmp;
} else {
Log.d("Bruce1", "used:" + used + " set doing false");
x = velocity * (t1 + 2 * t2);
y = 0;
doing = false;
}
}
public double getX() {
return x;
}
public double getY() {
return getMirrorY(animationSurfaceView.getHeight(), animationSurfaceView.getIcon().getHeight());
}
/**
* 反轉(zhuǎn)Y軸正方向踏兜。適應手機的真實坐標系词顾。
*/
public double getMirrorY(int parentHeight, int bitHeight) {
int half = parentHeight >> 1;
double tmp = half + (half - y);
tmp -= bitHeight;
return tmp;
}
public boolean doing() {
return doing;
}
public void cancel() {
doing = false;
}
}
這個小的demo是在15年時候?qū)懙牧耍缬绣e誤碱妆。肉盹。。