前言

很久之前,在简书上看到一个圆形双曲线波浪的进度条的文章,感觉很不错,结果,看一下代码,却是IOS的,嗯,其实github上也有很多android的双曲线动画,不过,我看了几个控件的源码(这个有空在分析),看不懂~原谅我把数学扔给体育老师了,里面涉及到 反余弦函数,还有Matrix的使用,好吧,这个我是真的不是很懂,然后,决定自己写一个,效果:

在文章的结尾,我会贴上代码地址。事实上,我写这篇文章的主要目的,更多是希望能描述清楚这个控件的使用,以及这个控件如何画出来。有过真实开发的同学都知道,需求千奇百怪,你永远不会知道产品下一个改动是什么。


准备

事实上,我并不准备重复我以前写过的东西,这里我只会简述一下几个API的使用:

path.quadTo()  参数为绝对位置
path.rQuadTo() 参数为相对前一个点的相对位置

上面这两个API如果不是很明白的话,可以看下我以前的一篇文章 Android 双曲线波浪动画(第一发),这篇文章里面你可以看到我很详细的讲述了这两个API的不同,当然,你还可以欣赏到我灵魂画师般的画技^-^。

path.arcTo  添加一个圆弧到path,如果圆弧的起点和上次最后一个坐标点不相同,就连接两个点

上面的解释感觉好抽象,举个实际简单的列子:

假设这是一个左上角是原点的矩形,x轴边长 = 20, y轴边长 = 10,那么如图,我想要填充如图的形状,那么问题主要就是怎么连接 B – C。
伪代码:

path.moveTo(0, 0);  从 0,0 出发
path.lineTo(5, 0);  A 连接到 C
Rect rect = new Rect(0, 0, 20, 10); 整个矩形的Rect对象
path.arcTo(rect, 180, 90, true); 180 代表着开始的角度,90代表着需要绘制的角度, true的意思就是:将最后一个点移动到圆弧起点,即不连接最后一个点与圆弧起点,你可以理解为只绘制路径,不填充圆弧,填充圆弧的话,就会变成三角的形状了

至此,如果你确实理解了以上的方法,那么接下来就是一些细节了,如果还是不太明白,那么接下来的篇幅,希望能帮助你理解。


代码思路

秉承着本人的习惯,代码就是思路,并且,最清楚的方法莫过于 onDraw。

onDraw :

    @Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(cavans_bg);if (progress > 0 && progress < max)drawWave(canvas);else if (progress == max)canvas.drawColor(front_wave_color);drawText(canvas);if (shape.equals(CIRCLE))drawArcs(canvas);}

整个绘制,我分为了三部分: drawWave ( 绘制动态波浪 ) , drawText(绘制文字), drawArcs(绘制四角的伪三角形)。

先来看看简单的部分,drawText 和 drawArcs

drawText:很简单的代码,默认情况下绘制在控件中心

// 默认情况下的值,side_lenght 是正方形的边长。if (text_margin_top == 0)text_margin_top = (int) (side_length / 2 + (fontMetrics.descent - fontMetrics.ascent) / 2);protected void drawText(Canvas canvas) {if (text_follow_progress)text = progress + PERCENT_CHAR;int textLength = (int) textPaint.measureText(text);int i = (side_length - textLength) / 2;canvas.drawText(text, i, text_margin_top, textPaint);}

drawArcs: 其实就是以 左上,右上,右下,左下 的顺序绘制了四个伪三角形。

    protected void drawArcs(Canvas canvas) {pathPaint.setColor(arcColor);path.reset();path.moveTo(half_side_length, 0);path.arcTo(rectf, 180, 90, true);path.lineTo(0, 0);path.close();canvas.drawPath(path, pathPaint);path.reset();path.moveTo(half_side_length, 0);path.arcTo(rectf, 270, 90, true);path.lineTo(side_length, 0);path.close();canvas.drawPath(path, pathPaint);path.reset();path.moveTo(side_length, 0);path.arcTo(rectf, 0, 90, true);path.lineTo(side_length, side_length);path.close();canvas.drawPath(path, pathPaint);path.reset();path.moveTo(half_side_length, side_length);path.arcTo(rectf, 90, 90, true);path.lineTo(0, side_length);path.close();canvas.drawPath(path, pathPaint);}

在看完简单的代码后,就可以来看看主要的代码 drawWave,对了,在看 drawWave 之前,需要看下一些参数的含义,以及参数的计算,我将这些步骤大都放在 onSizeChanged 方法中,也就是当 onMeasure 方法完全调用完成,完成了对 View 宽高的测量之后,再来计算我需要的值。

onSizeChanged

    @Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);
//        Log.d(TAG, "w = " + w + " : h = " + h);// 整个控件的矩形区间对象rectf = new RectF(0, 0, side_length, side_length);// side_length 其实就是矩形的边长,因为这个矩形是个正方形// 下面三行代码分别计算了 二分之一、四分之一、以及 八分之一 的边长值half_side_length = side_length / 2;quarter_side_length = half_side_length / 2;eighth_side_length = quarter_side_length / 2;//计算每一个进度的高度percent_height = side_length / max;// 默认情况下,波浪的振幅if (dwave == -1)dwave = side_length / 40 * 3;if (text_margin_top == 0)text_margin_top = (int) (side_length / 2 + (fontMetrics.descent - fontMetrics.ascent) / 2);initPaints();}

drawWave:注释会详细的写在代码里

 protected void drawWave(Canvas canvas) {//计算当前进度的高度int wave_height = side_length - progress * percent_height;// baseX 是波浪起始点的 X 轴坐标,其中 dx 是用来控制变化起始点的位置的// 之后会贴出 dx 的变化代码int baseX = -side_length + dx;if (baseX > 0)baseX = 0;//先绘制底部的波浪path.reset();pathPaint.setColor(behind_wave_color);path.moveTo(baseX, wave_height);for (int i = 0; i < 2; i++) {path.rQuadTo(quarter_side_length, -dwave, half_side_length, 0);path.rQuadTo(quarter_side_length, dwave, half_side_length, 0);}path.lineTo(side_length, side_length);path.lineTo(0, side_length);path.close();canvas.drawPath(path, pathPaint);//再绘制顶部的波浪// 注意:这里我默认写死了起始点的 X 坐标比 底部波浪的起始坐标 向左偏离 八分之一的宽度,这样两层波浪的效果才会逼真一点,同步的话会感觉很怪异path.reset();pathPaint.setColor(front_wave_color);path.moveTo(baseX - eighth_side_length, wave_height);for (int i = 0; i < 3; i++) {path.rQuadTo(quarter_side_length, dwave, half_side_length, 0);path.rQuadTo(quarter_side_length, -dwave, half_side_length, 0);}path.lineTo(side_length, side_length);path.lineTo(0, side_length);path.close();canvas.drawPath(path, pathPaint);}

dx 的变化代码:一个简单的属性动画

  public void startWaveAnimation() {animation = true;int value = 0;if (side_length == 0)value = Math.min(width, height);else if (height == width && height == 0)value = side_length;elsevalue = Math.min(side_length, Math.min(width, height));valueAnimator = ValueAnimator.ofInt(0, value);valueAnimator.setDuration(wave_duration);valueAnimator.setRepeatCount(ValueAnimator.INFINITE);valueAnimator.setInterpolator(new LinearInterpolator());valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {dx = (int) valueAnimator.getAnimatedValue();if (animation)postInvalidate();}});valueAnimator.start();}

总结

到这里其实整个控件就没什么好说的了,其他的只是一些零碎的细节,以及bug 的修复代码。其实本周计划是出两篇博客的,一篇是自己写的控件,就是本篇,另一篇是对 github 上开源控件的源码解读,然而,就像开篇所述,反三角函数 和 Matrix 把我拦住了,不过,一定会写的,等我把数学捡起来,给自己定个小目标:下星期完成。

源码地址

WaveProgressBar

WaveProgressBar -- 波浪进度条相关推荐

  1. Android魔术——手把手教你实现水晶球波浪进度条

    目录 1.效果展示 2.波浪函数 3.波浪填充 1)原理分析 2)代码实现 4.实现波浪运动效果 1)实现横向运动 2)实现波浪消退效果 5.总结 源码: 1.效果展示 本篇文章讲解如何实现一个水晶球 ...

  2. Flutter波浪进度条WaveProgressBar

    前一段时间,web端的同事想实现一个海浪进度条,但是他不知道怎么去实现,我这个人比较热心,就跑去写起了web程序,眼看就要完成了,他却跑去用echart,得,不用算了,我去写大Flutter的实现,然 ...

  3. 自定义安卓波浪进度条展示

    千呼万唤始出来,先上GIF看效果啦. 这边网络问题MarkDown进不去所以老的编辑模式大家凑合着看,博主顶着4G在更新博客希望大家支持. 加入有一天你们boss说,诶小明(一个程序猿)啊,今天我们这 ...

  4. css实现波浪进度条动画

    效果图 代码 <!DOCTYPE html> <html> <head><meta charset="UTF-8"><meta ...

  5. Android自定义波浪加载圆形进度条——(自定义控件 一)

    2019独角兽企业重金招聘Python工程师标准>>> 自定义控件-- 波浪形状圆形进度加载 时间管理的基础是精力管理,精力的高低.正负分影响到我们的效率 而时间是无法管理的,能够管 ...

  6. android录音波浪动画_Android 自定义 view 实现波浪动画进度条

    最近在做项目时需要实现这样一种动画,类似于波浪形的进度动画,粗略的看了一下,发现好像类似于正余弦曲线实现的,但是Android 没有相关的API,所以需要我们动手画出来,所以现在在此记录一下学习过程, ...

  7. android 环形时间显示_Android自定义波浪加载圆形进度条——(自定义控件 一)...

    自定义控件-- 波浪形状圆形进度加载 时间管理的基础是精力管理,精力的高低.正负分影响到我们的效率 而时间是无法管理的,能够管理的只有自己,透过管理自己的习惯,管理自己的事件来达成对时间的管理. 而在 ...

  8. android 图片处理过程中添加进度条,『Android自定义View实战』给我一个图标,还你一个水波纹进度球...

    前言 我们都知道,平时表现进度的方式有千千万万种(没有UI想不到的,只有你做不到的= =.),其中有一种就是水波纹进度球的形式,网上很多种实现都是直接采用纯色填充的方式,即水波纹都是纯颜色填充,效果看 ...

  9. android 进度条_Android仿水波纹流球进度条控制器,实现高端大气的主流特效

    今天看到一个效果挺不错的,就模仿了下来,加上了一些自己想要的效果,感觉还不错的样子,所以就分享出来了,话不多说,上图 CircleView 这里主要是实现中心圆以及水波特效 package com.l ...

最新文章

  1. R语言dplyr包使用mutate函数生成新的数据列(不改变原数据列)实战
  2. 用C语言实现分治方法数组的排序,C语言实现分治法实例
  3. 求二叉树指定结点到根的路径c语言,二叉树根节点到叶子结点和为指定值的路径...
  4. oracle收集统计信息sql,Oracle自动统计信息的收集原理及实验
  5. python3字典写入excel_python3:excel操作之读取数据并返回字典 + 写入的案例
  6. 使用While循环语句值得注意的事
  7. 如何在支付宝成为增加个人服务器,支付宝支付,服务器如何生成支付订单
  8. H265框架编码流程(一)
  9. iChart--地图显示人口统计
  10. far html 制作chm,CHM格式制作软件Far使用技巧
  11. 洛谷P3376【模板】网络最大流
  12. ROC(AUC)的显著性检验
  13. Internet Explorer无法打开internet站点文件.....操作终止
  14. FileZilla文件下载的目录
  15. 数据防泄密方案与需求匹配程度分析
  16. 泰坦尼克号乘客生存情况预测分析之第三部分建模及模型评价
  17. 立创EDA怎么批量处理元器件
  18. 【软件测试】:电梯、杯子、笔、桌子、洗衣机,设计测试用例?
  19. 计算机测试word总是零分,word excel做好后评分为什么是0分
  20. 创业实践案例课程报告

热门文章

  1. 内网渗透-msf及socks代理转发
  2. 地籍管理 : 宗地数据处理的一般步骤
  3. 搞定Markdown中的图片,一劳永逸的方法!
  4. 新书隆重推介:网络协议本质论(2011年8月面世,沤心沥血之作)
  5. kafka源码分析之producer
  6. Trie 字典树【Leo_Jose】
  7. 又学到了一个重要的公式,点到直线的距离,欧耶,为自己鼓掌
  8. 项目商业模式的设计与思考
  9. Win7 中IIS配置
  10. CefSharp 浏览器打开多个