## 实现原理

1. 准备工作 测量布局，初始化画笔，绘制图片，绘制贝塞尔曲线等
绘制如下图所示：

2. 让小红心动起来

## 代码实现

``````@SuppressLint("DrawAllocation")
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
wight = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(wight, height);
random = new Random();
mStartPoint.x = wight / 2;
mStartPoint.y = height;
mEndPoint.x = wight / 2;
mEndPoint.y = 0;

mConOnePoint.x = wight;
mConOnePoint.y = height * 3 / 4;

mConTwoPoint.x = 0;
mConTwoPoint.y = height / 4;

//随机数控制心出现的位置
offestplusorminus = random.nextInt(2);
Log.e("offestplusorminus", offestplusorminus + "");
if (offestplusorminus == 1) {//位移为正
offest = random.nextInt(200);
Log.e("offestplusorminus", "正");
} else {//位移为负
int minus = random.nextInt(200);
Log.e("offestplusorminus", "负");
offest = -minus;
}
}
``````

`````` @Override
protected void onDraw(Canvas canvas) {
drawLove(canvas);
}

public void drawLove(Canvas canvas) {
mRoutePaint.setAlpha((int) alpha);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.love);
bapwidht = bitmap.getWidth();
bapheight = bitmap.getHeight();
Matrix matrix = new Matrix();
matrix.postTranslate(wight - value.x - offest, height - value.y);//高度不需要减bitmap本身高度，初始不用漏出心，否则会出现位移BUG
canvas.drawBitmap(bitmap, matrix, mRoutePaint);
//绘制贝塞尔曲线
mpath.reset();
mpath.moveTo(mEndPoint.x - offest, mEndPoint.y);//初始点 从下往上 贝塞尔曲线终止点为起始点
mpath.cubicTo(mConOnePoint.x - offest, mConOnePoint.y, mConTwoPoint.x - offest, mConTwoPoint.y, mStartPoint.x - offest, mStartPoint.y);//控制点 和终止点
/* canvas.drawPath(mpath, mRoutePaint);*/
canvas.save();
}
``````

``````   public void addStar() {
//设置属性动画
valueAnimator = ValueAnimator.ofObject(new StarTypeEvaluator(mConOnePoint, mConTwoPoint), mEndPoint,
mStartPoint);
valueAnimator.setDuration(6000);
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Point point = (Point) animation.getAnimatedValue();
value.x = point.x;
value.y = point.y;
if (point.y >= height / 2) {
alpha -= 4;//透明度不断减少
}
if (alpha < 0) {
alpha = 0;
}
postInvalidate();
}
});
valueAnimator.start();//开始动画
//监听动画结束
@Override
public void onAnimationEnd(Animator animation) {
alpha = 255;//透明度重置
//0，1，2随机数
offestplusorminus = random.nextInt(2);
if (offestplusorminus == 1) {//位移为正
offest = random.nextInt(200);
} else {//位移为负
int minus = random.nextInt(200);
offest = -minus;
}
postInvalidate();
}
});*/

}
``````

//动画估值器
class StarTypeEvaluator implements TypeEvaluator {

``````    //记录控制点
private Point conOnePoint, conSecondPoint;

public StarTypeEvaluator(Point conOnePoint, Point conSecondPoint) {
this.conOnePoint = conOnePoint;
this.conSecondPoint = conSecondPoint;
}

@Override
public Point evaluate(float t, Point startValue, Point endValue) {

//利用三阶贝塞尔曲线公式算出中间点坐标
int x = (int) (startValue.x * Math.pow((1 - t), 3) + 3 * conOnePoint.x * t * Math.pow((1 - t), 2) + 3 *
conSecondPoint.x * Math.pow(t, 2) * (1 - t) + endValue.x * Math.pow(t, 3));
int y = (int) (startValue.y * Math.pow((1 - t), 3) + 3 * conOnePoint.y * t * Math.pow((1 - t), 2) + 3 *
conSecondPoint.y * Math.pow(t, 2) * (1 - t) + endValue.y * Math.pow(t, 3));
return new Point(x, y);
}
}
``````

``````  mViewGroup = (ViewGroup) getWindow().getDecorView();
@Override
public void onClick(View v) {
floatLove = new FloatLove(MainActivity.this);
}
});
``````