先上个效果图看看
直接上代码了,比较忙没时间详细剖析~~相信大家能看懂
//核心部分
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawCircle(canvas);
drawLightWave(canvas);
drawDarkWave(canvas);
}
/**
* 绘制浅色波浪(贝塞尔曲线)
*
* @param canvas
*/
private void drawLightWave(Canvas canvas) {
mWavePaint.setColor(LightWaveColor);
//从右向左的水波位移应该被减去
drawWave(canvas, mWavePaint, mLightPoints, isR2L ? -mLightWaveOffset : mLightWaveOffset);
}
@TargetApi(Build.VERSION_CODES.KITKAT)
private void drawWave(Canvas canvas, Paint paint, Point[] points, float waveOffset) {
mWaveLimitPath.reset();
mWavePath.reset();
float height = lockWave ? 0 : mRadius - 2 * mRadius * mPercent;
//moveTo和lineTo绘制出水波区域矩形
mWavePath.moveTo(points[0].x + waveOffset, points[0].y + height);
for (int i = 1; i < mAllPointCount; i += 2) {
mWavePath.quadTo(points[i].x + waveOffset, points[i].y + height,
points[i + 1].x + waveOffset, points[i + 1].y + height);
}
mWavePath.lineTo(points[mAllPointCount - 1].x, points[mAllPointCount - 1].y + height);
//不管如何移动,波浪与圆路径的交集底部永远固定,否则会造成上移的时候底部为空的情况
mWavePath.lineTo(points[mAllPointCount - 1].x, mCenterPoint.y + mRadius);
mWavePath.lineTo(points[0].x, mCenterPoint.y + mRadius);
mWavePath.close();
mWaveLimitPath.addCircle(mCenterPoint.x, mCenterPoint.y, mRadius, Path.Direction.CW);
//取该圆与波浪路径的交集,形成波浪在圆内的效果
mWaveLimitPath.op(mWavePath, Path.Op.INTERSECT);
canvas.drawPath(mWaveLimitPath, paint);
}
/**
* 绘制深色波浪(贝塞尔曲线)
*
* @param canvas
*/
private void drawDarkWave(Canvas canvas) {
//底部的字
mPercentPaint.setColor(Color.RED);
String text = "24GB";
drawCenterText(canvas, mPercentPaint, text);
//上层的字
mPercentPaint.setColor(Color.WHITE);
//生成闭合波浪路径
mWavePath = getActionPath(currentPercent);
mWavePaint.setColor(DarkWaveColor);
//新建图层实现离屏缓冲
int flag = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG);
//绘制蓝色波浪
canvas.drawPath(mWavePath, mWavePaint);
mWavePaint.setXfermode(xfermode);
//用带有SRC_IN模式的画笔绘制圆形图像,这样圆和波浪相交的地方就只显示圆了
canvas.drawBitmap(bitmap, 0, 0, mWavePaint);
mPercentPaint.setXfermode(xfermode_text);
//用带有SRC_ATOP的文字画笔绘制文字,这样在圆形波浪和文字相交的地方绘制文字,在不相交的地方绘制圆形波浪
drawCenterText(canvas, mPercentPaint, text);
//合并图层到canvas上
canvas.restoreToCount(flag);
mPercentPaint.setXfermode(null);
mWavePaint.setXfermode(null);
}
private Path getActionPath(float percent) {
Path path = new Path();
int x = -mWidth;
//当前x点坐标(根据动画进度水平推移,一个动画周期推移的距离为一个mWidth)
x += percent * mWidth;
//波形的起点
path.moveTo(x, mHeight / 2);
//控制点的相对宽度
int quadWidth = mWidth / 4;
//控制点的相对高度
int quadHeight = mHeight / 20 * 3;
//第一个周期
path.rQuadTo(quadWidth, quadHeight, quadWidth * 2, 0);
path.rQuadTo(quadWidth, -quadHeight, quadWidth * 2, 0);
//第二个周期
path.rQuadTo(quadWidth, quadHeight, quadWidth * 2, 0);
path.rQuadTo(quadWidth, -quadHeight, quadWidth * 2, 0);
//右侧的直线
path.lineTo(x + mWidth * 2, mHeight);
//下边的直线
path.lineTo(x, mHeight);
//自动闭合补出左边的直线
path.close();
return path;
}
private void drawCenterText(Canvas canvas, Paint textPaint, String text) {
Rect rect = new Rect(0, 0, mWidth, mHeight);
textPaint.setTextAlign(Paint.Align.CENTER);
Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
//文字框距顶部文字基线的距离
float top = fontMetrics.top;
//文字框底部距文字基线的距离
float bottom = fontMetrics.bottom;
int centerY = (int) (rect.centerY() - top / 2 - bottom / 2);
canvas.drawText(text, rect.centerX(), centerY, textPaint);
}
/**
* 绘制圆形bitmap
*
* @param width
* @param height
* @return
*/
private Bitmap getCircleBitmap(int width, int height) {
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
// bitmap.eraseColor(Color.parseColor("#FF0000"));//填充颜色
Canvas canvas = new Canvas(bitmap);
canvas.drawCircle(width / 2, height / 2, width / 2, mWavePaint);
return bitmap;
}
直接新建一个类复制进去就可以直接使用,其中还有一点点不完善的地方,待后续更新文章