贝塞尔(bezier)曲线实现竖直方向波浪

使用贝塞尔曲线实现Android自定义View,竖直方向的波浪。

贝塞尔曲线

贝塞尔曲线可实现很多复杂的动画效果,如QQ的”一键下班”小红点拖拽效果等
贝塞尔曲线分为一阶贝塞尔曲线、二阶贝塞尔曲线、三阶贝塞尔曲线…高阶贝塞尔曲线
一阶贝塞尔曲线没有控制点,仅有起始和结束点(P0和P1),即一个线段(Path类的lineTo实现)
一阶贝塞尔曲线
二阶贝塞尔曲线有一个控制点(P1),起始和结束点(P0和P2),来描述曲线状态(Path类的quadTo实现)
二阶贝塞尔曲线
三阶贝塞尔曲线有两个控制点(P1和P2),起始和结束点(P0和P3),来描述曲线状态(Path类的cubicTo实现)
三阶贝塞尔曲线

自定义BezierWave实现竖直方向波浪

效果图

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public class BezierWave extends View {
private Paint mPaint;
private Path mPath;
private int mWaveLength = 400;
private int mOffset;
private int mScreenHeight;
private int mScreenWidth;
private int mWaveCount;
private float centerX;
private AnimatorSet mAnimSet;
public BezierWave(Context context) {
super(context);
}
public BezierWave(Context context, AttributeSet attrs) {
super(context, attrs);
mPath = new Path();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(getResources().getColor(R.color.wave_color));
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
public BezierWave(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mScreenHeight = h;
mScreenWidth = w;
mWaveCount = 8;
centerX = mScreenWidth * centerX;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPath.reset();
mPath.moveTo(centerX, -mWaveLength + mOffset);
for (int i = 0; i < mWaveCount; i++) {
// + (i * mWaveLength)
// + mOffset
mPath.quadTo(centerX + 30, (-mWaveLength * 3 / 4) + (i * mWaveLength) + mOffset, centerX, (-mWaveLength / 2) + (i * mWaveLength) + mOffset);
mPath.quadTo(centerX - 30, (-mWaveLength / 4) + (i * mWaveLength) + mOffset, centerX, i * mWaveLength + mOffset);
}
mPath.lineTo(mScreenWidth, mScreenHeight);
mPath.lineTo(mScreenWidth, 0);
mPath.close();
canvas.drawPath(mPath, mPaint);
}
public void setCenterX(float centerX) {
this.centerX = centerX;
}
public void startAnim() {
mAnimSet = new AnimatorSet();
// wave animation
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, mWaveLength);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setDuration(2000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mOffset = (int) animation.getAnimatedValue();
postInvalidate();
}
});
// translate animation
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this,"translationX",0.0f, 200.0f).setDuration(8000);
mAnimSet.playTogether(valueAnimator,objectAnimator);
mAnimSet.start();
}
public void stopAnim() {
mAnimSet.end();
}
}