實現效果:
思路:
1.首先要給心形圖片創建一個平滑的懸浮路徑,那就要用到貝塞爾曲線,這裏採用自定義TypeEvaluator實現。
2.路徑有了,就要考慮實現動畫的兩個步驟
a.縮放,伴隨透明度變化
b.底部懸浮到頂部
這裏是用的是Matrix
3.自定義View,然後繪製心形圖片。
詳細步驟,看源碼
代碼:
1.自定義BezierEvaluator
package com.test.paintdemo.loveflyover;
import android.animation.TypeEvaluator;
import android.graphics.PointF;
/**
* Created by ygdx_lk on 17/6/26.
*/
public class BezierEvaluator implements TypeEvaluator<PointF> {
private final PointF p0, p3;
public BezierEvaluator(PointF point0, PointF point3){
this.p0 = point0;
this.p3 = point3;
}
@Override
public PointF evaluate(float t, PointF p1, PointF p2) {
//貝塞爾曲線的三次方公式
PointF pointF = new PointF();
pointF.x = (float) (p0.x * Math.pow((1 - t), 3) + 3 * p1.x * t * Math.pow((1 - t), 2) + 3 * p2.x * Math.pow(t, 2) * (1 - t) + p3.x * Math.pow(t, 3));
pointF.y = (float) (p0.y * Math.pow((1 - t), 3) + 3 * p1.y * t * Math.pow((1 - t), 2) + 3 * p2.y * Math.pow(t, 2) * (1 - t) + p3.y * Math.pow(t, 3));
return pointF;
}
}
2.創建FlyOverModel
package com.test.paintdemo.loveflyover;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import com.test.paintdemo.R;
import java.util.Random;
/**
* Created by ygdx_lk on 17/6/26.
*/
public class FlyOverModel {
private static final String TAG = "FlyOverModel";
private Paint mPaint;
private PointF p0, p1, p2, p3;//p0起點,p1、p2拐點,p3終點
private float love_w, love_h;//愛心的寬高
private Bitmap mBitMap;//圖片
private Matrix matrix;
//圖片
private int[] resources = {R.drawable.red, R.drawable.blue, R.drawable.yellow};
//差值器
private Interpolator[] interpolator = {new AccelerateDecelerateInterpolator(),
new AnticipateInterpolator(),
new OvershootInterpolator(),
new AnticipateOvershootInterpolator(),
new LinearInterpolator(),
new AccelerateInterpolator(),
new DecelerateInterpolator()
};
public FlyOverModel(final Context context, final int width, final int height, final Invalidate invalidate){
//初始化畫筆
mPaint = new Paint();
mPaint.setAntiAlias(true);
//矩陣變換,用來控制圖片的縮放位移
matrix = new Matrix();
//三次方貝塞爾曲線:初始化四個點,p0起點,p1、p2拐點,p3終點
p0 = new PointF();
p1 = new PointF();
p2 = new PointF();
p3 = new PointF();
//初始化bitmap
mBitMap = BitmapFactory.decodeResource(context.getResources(), resources[new Random().nextInt(resources.length)]);
//獲取bitmap的寬高
love_w = mBitMap.getWidth();
love_h = mBitMap.getHeight();
//p0正好將圖片貼底居中顯示
p0.x = (width - love_w) / 2;
p0.y = height - love_h;
p2.x = (float) (Math.random() * width);
p2.y = (float) (Math.random() * height / 2);
p1.x = (float) (Math.random() * width);
p1.y = (float) ((1 + Math.random()) * height / 2);
//p3正好圖片移出屏幕
p3.x = (float) (Math.random() * width);
p3.y = -love_h;
//縮放動畫
ValueAnimator scaleAnimator = ValueAnimator.ofFloat(0, 1);
scaleAnimator.setDuration(1000);
scaleAnimator.setInterpolator(new LinearInterpolator());
scaleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//平移到底部
matrix.setTranslate(p0.x, p0.y);
//以圖片中心底部爲軸,進行縮放
matrix.preScale(animation.getAnimatedFraction(), animation.getAnimatedFraction(), love_w / 2, love_h);
//設置畫筆透明度
mPaint.setAlpha((int) (255 * animation.getAnimatedFraction()));
invalidate.invalidate();
}
});
//位移動畫
BezierEvaluator bezierEvaluator = new BezierEvaluator(p0, p3);
ValueAnimator valueAnimator = ValueAnimator.ofObject(bezierEvaluator, p1, p2);
valueAnimator.setInterpolator(interpolator[new Random().nextInt(interpolator.length)]);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
matrix.reset();
matrix.setTranslate(pointF.x, pointF.y);
invalidate.invalidate();
}
});
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(valueAnimator).after(scaleAnimator);
animatorSet.start();
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
//如果動畫結束了,重新開始動畫
animation.start();
super.onAnimationEnd(animation);
}
});
}
interface Invalidate{
void invalidate();
}
/**
* 繪製bitmap
* @param canvas
*/
public void drawBitmap(Canvas canvas){
canvas.drawBitmap(mBitMap, matrix, mPaint);
}
}
3.創建自定義View:LoveFlyOver
package com.test.paintdemo.loveflyover;
import android.content.Context;
import android.graphics.Canvas;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
/**
* Created by ygdx_lk on 17/6/26.
*/
public class LoveFlyOver extends View {
private int width;//控件寬
private int height;//控件高
private static final String TAG = "loveFlyOver";
private List<FlyOverModel> list;
public LoveFlyOver(Context context) {
this(context, null);
}
public LoveFlyOver(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
list = new ArrayList<>();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//控件寬高
width = w;
height = h;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
//點擊後添加圖片
addLove();
break;
}
return super.onTouchEvent(event);
}
private void addLove(int count){
for (int i = 0; i < count; i++) {
addLove();
}
}
//添加心形圖片
private void addLove(){
FlyOverModel flyOverModel = new FlyOverModel(getContext(), width, height, new FlyOverModel.Invalidate() {
@Override
public void invalidate() {
postInvalidate();
}
});
list.add(flyOverModel);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//繪製
for (FlyOverModel item : list) {
item.drawBitmap(canvas);
}
}
}