Wave动画效果

项目地址:Github

动画效果:

image

实现波浪wave效果,以及水位位置调整。

代码实现

外部形状

外部形状可以是圆形,三角形,整个图形的绘制区域由canvas决定

初始化paint

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

private void initBoarderPaint() {
//默认的style是fill,填充的
mBoarderPain = new Paint();
mBoarderPain.setAntiAlias(true);
mBoarderPain.setStyle(Paint.Style.STROKE);//描边
mBoarderPain.setStrokeWidth(DEFAULT_BOARD_WIDTH);
mBoarderPain.setColor(Color.RED);
}

private void initBgPaint() {
//默认的style是fill,填充的
mBgPaint = new Paint();
mBgPaint.setAntiAlias(true);
mBgPaint.setColor(getResources().getColor(R.color.voicebg));
}

在onDraw中绘制

1
2
3
4
5
6
7
8
9
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float boaderwidth = DEFAULT_BOARD_WIDTH;

canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, (getWidth() - boaderwidth) / 2f - 1f, mBoarderPain);//画边框
canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, getWidth() / 2f - boaderwidth, mBgPaint);//画圆形背景

}

怎么画波浪呢?

初始化paint

1
2
3
4
5
6
private void initWavePaint() {
mWavePain = new Paint();
mWavePain.setAntiAlias(true);
mWavePain.setColor(getResources().getColor(R.color.voicefr));
updateWaveShader();
}

其中updateWaveShader,使用的着色器是BitmapShader。

1
2
3
4
5
6
7
private void updateWaveShader() {
if (getWaveBitmap() != null) {
mWaveShader = new BitmapShader(getWaveBitmap(), Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);//x坐标repeat模式,y方向上最后一个像素重复
mWavePain.setShader(mWaveShader);
} else {
mWavePain.setShader(null);
}

而getWaveBitmap()的任务是获得一个画有两个波浪的图形

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
private Bitmap getWaveBitmap() {//返回一个波形的图案,两条线

int wavecount = 1;//容纳多少个完整波形


int width = getMeasuredWidth();
int height = getMeasuredHeight();
Log.i("linlian", "width=" + width + " height=" + height);
if (width > 0 && height > 0) {

Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas waveLineCanvas = new Canvas(bitmap);


//坐标点数组,x从0-width,y=Asin(Wx+Q)+H
// W = 2*PI/width
// A = height
// h = height
// Q = 0
final int endX = width + 1;
final int endY = height + 1;
float W = (float) (2f * Math.PI * wavecount / width);
float A = height / 10f;//波浪幅度在整体的10分之一
float H = height / 2;//默认水位在一半的位置
float[] waveY = new float[endX];

for (int x = 0; x < endX; x++) {
waveY[x] = (float) (A * Math.sin(W * x)) + H;
}

int xShift = width / 4;
mWavePaint.setColor(getResources().getColor(R.color.wavebg));
for (int x = 0; x < endX; x++) {
waveLineCanvas.drawLine(x, waveY[(x + xShift) % endX], x, endY, mWavePaint);// .:|:. 像这样画线
}
mWavePaint.setColor(getResources().getColor(R.color.wavefr));
for (int x = 0; x < endX; x++) {

waveLineCanvas.drawLine(x, waveY[x], x, endY, mWavePaint);// .:|:. 像这样画线
}

return bitmap;
}
return null;
}

设置好图形着色器之后,在view的onDraw方法上,添加

1
2
3
4
5
6
7
8
9
10
11
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float boaderwidth = DEFAULT_BOARD_WIDTH;

canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, (getWidth() - boaderwidth) / 2f - 1f, mBoarderPain);//画边框
canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, getWidth() / 2f - boaderwidth, mBgPaint);//画圆形背景


canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, getWidth() / 2f - boaderwidth, mWavePain);//画波浪图形
}

如何实现动画效果呢

通过属性动画来实现,改变waveXshift的值,从0到1变化,两秒,重复变化

1
2
3
4
5
6
7
8
9
10
private void initAnimation() {
mShaderMatrix = new Matrix();
ObjectAnimator waveXshiftAnimator = ObjectAnimator.ofFloat(this, "waveXshift", 0f, 1f);
waveXshiftAnimator.setRepeatCount(ValueAnimator.INFINITE);
waveXshiftAnimator.setDuration(2000);
waveXshiftAnimator.setInterpolator(new LinearInterpolator());
mAnimatorset = new AnimatorSet();
mAnimatorset.play(waveXshiftAnimator);

}

属性变化的时候,重新绘制

1
2
3
4
5
6
7
public void setWaveXshift(float mWaveXshift) {
if (this.mWaveXshift != mWaveXshift) {
this.mWaveXshift = mWaveXshift;
//变化的是重新绘制view,实现动画效果
invalidate();
}
}

在onDraw中,实现图像的水平移动 mWaveXshift * getWidth();

1
2
3
4
5
6
7
8
9
10
11
if (mWaveShader != null) {
if (mWavePaint.getShader() == null) {
mWavePaint.setShader(mWaveShader);
}
float dx = mWaveXshift * getWidth();
mShaderMatrix.setTranslate(dx, 0);//平移波浪,实现推进效果
mWaveShader.setLocalMatrix(mShaderMatrix);
} else {
mWavePaint.setShader(null);
}
canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, getWidth() / 2f - boaderwidth, mWavePaint);//画波浪

重新实现的代码可以参考

https://github.com/lynn8570/VoiceView/blob/master/animlib/src/main/java/anim/lynn/voice/VoiceWave.java