HeartLineDemo

Android_HeartLineDemo

实现一个沿心形曲线运动的动画

用到的知识:

  • 自定义View初级
  • 贝塞尔曲线
  • path组合路径
  • Android属性动画之ObjectAnimator

先看一下实现的效果:
效果图

然后做了一个简单的实现,分为以下几个步骤

先画出轨迹的背景

自定义一个HeartView,重写onDraw方法


[title] [] [url] [link text]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint = new Paint();
paint.setStrokeWidth(6);
paint.setAntiAlias(true);
paint.setColor(Color.GRAY);
paint.setStyle(Paint.Style.STROKE);
int width = getWidth();
int height = getHeight();

Path path1 = new Path();
// 起点
float startW = width / 2;
float startH = height / 4;
// 终点
float endW = width / 2;
float endH = (height * 7) / 12;

path1.moveTo(endW, endH);
// 贝塞尔曲线
path1.cubicTo((width * 12) / 13, (height * 2) / 5, (width * 6) / 7, height / 9, startW, startH);
canvas.drawPath(path1, paint);

Path path2 = new Path();
path2.moveTo(width / 2, height / 4);
path2.cubicTo(width / 7, height / 9, width / 13, (height * 2) / 5, width / 2, (height * 7) / 12);

canvas.drawPath(path2, paint);
// 画线 辅助线
// canvas.drawLine(width/2,height/4,width / 7, height / 9,paint);
// canvas.drawLine( width / 2, (height * 7) / 12, width / 13, (height * 2) / 5,paint);
// canvas.drawLine(width / 7, height / 9, width / 13, (height * 2) / 5,paint);
canvas.drawLine(0, (height * 7) / 12, width, (height * 7) / 12, paint); //直线

}

用前人积累的经验画出一个类似心形的图,可以根据辅助线再自己适当微调。
并在底部加上一条直线作为轨迹的一部分。

设置动画行走的路径


[title] [] [url] [link text]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 

//获取背景轨迹
width = h.getWidth();
height = h.getHeight();
Log.d("mView", width + " " + height);
// 获取运动图片的宽高
float lWith = ic.getWidth() / 2;
float lHeight = ic.getHeight() / 2;
// 修正运动中心
float startW = width / 2 - lWith;
float startH = height / 4 - lHeight;
float endW = width / 2 - lWith;
float endH = (height * 7) / 12 - lHeight;
Path path = new Path();
// 心形右边
path.moveTo(endW, endH);
path.cubicTo((width * 12) / 13, (height * 2) / 5, (width * 6) / 7, height / 9, startW, startH);

// 心形左边
Path path2 = new Path();
path2.moveTo(width / 2 - lWith, height / 4 - lHeight);
path2.cubicTo(width / 7, height / 9, width / 13, (height * 2) / 5, width / 2 - lWith, (height * 7) / 12 - lHeight);

// 直线左边
Path p1 = new Path();
p1.moveTo(0 - lWith, (height * 7) / 12 - lHeight);
p1.lineTo(width / 2 - lWith, (height * 7) / 12 - lHeight);
// 直线右边
Path p3 = new Path();
p3.moveTo(width / 2 - lWith, (height * 7) / 12 - lHeight);
p3.lineTo(width - lWith, (height * 7) / 12 - lHeight);
Path myPath = new Path();
// 轨迹组合
myPath.addPath(p1);
myPath.addPath(path);
myPath.addPath(path2);
myPath.addPath(p3);


由于延轨迹运动的心是有自身大小的,但是运动是并不是沿view的中心运动的,而是左上顶部。
所以获取运动的view的宽高切半进行修正。这里只对起点和终点进行了修正,感觉辅助线段的影响不太明显,就没有做x处理了。

开启动画


[title] [] [url] [link text]
1
2
3
4
5
6
ObjectAnimator mAnimator;
mAnimator = ObjectAnimator.ofFloat(ic, View.X, View.Y, myPath);
mAnimator.setDuration(5000);
// 重复运动50次
mAnimator.setRepeatCount(50);
mAnimator.start();

附:
资料:
贝塞尔曲线介绍
模拟曲线


代码地址:
github仓库
*转载注明出处~如果对你有用欢迎给个Star~