归志宁无五亩园,读书本意在元元。这篇文章主要讲述Android自定义View——实现水波纹效果类似剩余流量球相关的知识,希望能为你提供帮助。
最近突然手痒就想搞个贝塞尔曲线做个水波纹效果玩玩,终于功夫不负有心人最后实现了想要的效果,一起来看下吧:效果图镇楼
文章图片
一:先一步一步来分解一下实现的过程
- 需要绘制一个正弦曲线(sin)或者余弦曲线(cos)
- 通过水平平移曲线来的到像水波波动的效果
- 水平移动的同时还需要有水位上涨,也就是向上平移
- 裁剪画布为圆形,在圆形区域绘制曲线
- 通过上面4步就可以实现了
文章图片
文章图片
???绘制贝塞尔曲线我们必须要知道三个点:起点、控制点、终点;有了这三个点我们就可以绘制一段简单二阶贝塞尔曲线。从图中我们可以看出 起点 控制点p1 x1 这三个点绘制了一段曲线,也就是通过path.quadTo()函数添加一个曲线路径。三:下面就来看下代码的实际操作了,这里就直接省略掉一些画笔初始化的操作了可以点击这里查看源码
???假设我们需要绘制一个周期的sin曲线,那么我们就只需要知道起点、一个周期的宽度、振幅;就可以绘制一个sin曲线了。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取view的宽度
width = getViewSize(800, widthMeasureSpec);
//获取view的高度
height = getViewSize(400, heightMeasureSpec);
//获取起点坐标
startPoint = new Point(0, height / 2);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
首先肯定是要获取到画布的大小才能确定好起点的坐标,有了起点坐标就可以开始绘制我们的曲线了在ondraw()函数中进行曲线的绘制
/*sin曲线 1/4个周期的宽度*/
private int cycle = 200;
/*sin曲线振幅的高度*/
private int waveHeight = 200;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
path.moveTo(startPoint.x, startPoint.y);
int j = 1;
//循环绘制正弦曲线 循环一次半个周期
for (int i = 1;
i <
= 8;
i++) {
if (i % 2 == 0) {
//波峰
path.quadTo(startPoint.x + (cycle * j), startPoint.y + waveHeight,
startPoint.x + (cycle * 2) * i, startPoint.y);
} else {
//波谷
path.quadTo(startPoint.x + (cycle * j), startPoint.y - waveHeight,
startPoint.x + (cycle * 2) * i, startPoint.y);
}
j += 2;
}
//绘制封闭的曲线
path.lineTo(width, height);
//右下角
path.lineTo(startPoint.x, height);
//左下角
path.lineTo(startPoint.x, startPoint.y);
//起点
path.close();
canvas.drawPath(path, paint);
}
- 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
文章图片
四:接下来就是水平移动这个曲线了为了移动起来更加好看,我们需要在屏幕外面开始绘制一个周期,如下:
//初始化的时候将起点移至屏幕外一个周期
startPoint = new Point(-cycle * 4, height / 2);
//继续在ondraw()函数最后追加平移代码//判断是不是平移完了一个周期
if (startPoint.x + 40 >
= 0) {
//满了一个周期则恢复默认起点继续平移
startPoint.x = -cycle * 4;
}
//每次波形的平移量 40
startPoint.x += 40;
postInvalidateDelayed(150);
path.reset();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
文章图片
五:接下来就是要将画布变成圆形了(其实还是个矩形,只是绘画区域在你所裁剪的区域),然后在里面实现水波纹就哦的K了;完整的绘制代码如下:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//裁剪画布为圆形
Path circlePath = new Path();
circlePath.addCircle(width / 2, height / 2, width / 2, Path.Direction.CW);
canvas.clipPath(circlePath);
canvas.drawPaint(circlePaint);
canvas.drawCircle(width / 2, height / 2, width / 2, circlePaint);
//以下操作都是在这个圆形画布中操作
//根据进度改变起点坐标的y值
startPoint.y = (int) (height - (progress / 100.0 * height));
//起点
path.moveTo(startPoint.x, startPoint.y);
int j = 1;
//循环绘制正弦曲线 循环一次半个周期
for (int i = 1;
i <
= 8;
i++) {
if (i % 2 == 0) {
path.quadTo(startPoint.x + (cycle * j), startPoint.y + waveHeight,
startPoint.x + (cycle * 2) * i, startPoint.y);
} else {
path.quadTo(startPoint.x + (cycle * j), startPoint.y - waveHeight,
startPoint.x + (cycle * 2) * i, startPoint.y);
}
j += 2;
}
//绘制封闭的曲线
path.lineTo(width, height);
//右下角
path.lineTo(startPoint.x, height);
//左下角
path.lineTo(startPoint.x, startPoint.y);
//起点
path.close();
canvas.drawPath(path, paint);
drawText(canvas, textPaint, progress + "%");
//判断是不是平移完了一个周期
if (startPoint.x + 40 >
= 0) {
//满了一个周期则恢复默认起点继续平移
startPoint.x = -cycle * 4;
}
//每次波形的平移量 40
startPoint.x += 40;
if (autoIncrement) {
if (progress >
= 100) {
progress = 0;
} else {
progress++;
}
}
postInvalidateDelayed(150);
path.reset();
}
推荐阅读
- Android开发笔记: 5种对话框案例
- Android中监控home键
- Log4j自定义Appender
- android学习之路资料集合
- Android的系统架构
- Android中的动画
- Android 7.1 SystemUI--任务管理
- 安卓rxjava内存泄漏
- Oracle NoLogging Append 方式减少批量insert的redo_size