效果展示:

原理解析:

首先构建一个圆形路径(中心点为控件中心),然后利用canvas.clipPath方法将画布裁剪为圆形。

利用贝赛尔曲线构造一条如上图所示的波浪线,波浪线分为三段(一起一伏为一段,每段长度为圆的直径长度),波浪线左端点到圆左端点为一段,圆中为一段,剩下的为一段。然后将波浪线的两端点与控件底部两点相连形成闭合路径。

然后将起始点A不断向右移动即可实现波浪的动画效果,而绿色部分的高度(进度)则是由相同的原理实现的,这里就不多做描述了。

代码展示:

public class WaveView extends View {private Paint mPaintWavw;//波浪画笔private Paint mPaintProgress;//进度画笔private float mItemWaveLength;//波浪长度private float mRadius;//圆的半径private float mWaveHeight = 20;//波浪的高度private float mProgressTextSize = 130 ;//进度文字的大小private Path mPathWave;//波浪路径(不透明)private Path mPathWaveAlpha;//波浪路径(半透明)private Path mPathCircle;//圆形球路径private float mWave=0;//波浪偏移量(实现波浪效果的关键)private float mProgress = 0;//进度private Paint.FontMetricsInt mFontMetricsInt;private ObjectAnimator mWaveobjectAnimator;public WaveView(Context context) {this(context,null);}public WaveView(Context context, @Nullable AttributeSet attrs) {this(context, attrs,0);}public WaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {setLayerType(LAYER_TYPE_SOFTWARE,null);mPaintWavw = new Paint(Paint.ANTI_ALIAS_FLAG);mPaintWavw.setColor(Color.parseColor("#33F92B"));mPaintWavw.setStyle(Paint.Style.FILL);mPaintProgress = new Paint(Paint.ANTI_ALIAS_FLAG);mPaintProgress.setStrokeWidth(10);mPaintProgress.setStrokeCap(Paint.Cap.ROUND);//设置笔帽为圆形mPaintProgress.setStrokeJoin(Paint.Join.ROUND);//设置拐角为圆形mPaintProgress.setColor(Color.WHITE);//将进度颜色设置为白色mPaintProgress.setTextAlign(Paint.Align.CENTER);mPathWave = new Path();mPathWaveAlpha = new Path();mPathCircle = new Path();}/*** 修改高度* @param widthMeasureSpec* @param heightMeasureSpec*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(measureWidth(widthMeasureSpec),measuredHeight(heightMeasureSpec));}/*** 测量宽* @param widthMeasureSpec*/private int measureWidth(int widthMeasureSpec) {int result ;int specMode = MeasureSpec.getMode(widthMeasureSpec);int specSize = MeasureSpec.getSize(widthMeasureSpec);if (specMode == MeasureSpec.EXACTLY){result = specSize;}else {result = 200;if (specMode == MeasureSpec.AT_MOST){result = Math.min(result,specSize);}}return result;}/*** 测量高* @param heightMeasureSpec*/private int measuredHeight(int heightMeasureSpec) {int result ;int specMode = MeasureSpec.getMode(heightMeasureSpec);int specSize = MeasureSpec.getSize(heightMeasureSpec);if (specMode == MeasureSpec.EXACTLY){result = specSize;}else{result = 200;if(specMode == MeasureSpec.AT_MOST){result = Math.min(result,specSize);}}return  result;}/*** 当控件大小发生改变的时候对一些数值进行调整以适应控件大小* @param w* @param h* @param oldw* @param oldh*/@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);mRadius = (float) (Math.min(w, h)*0.9/2);mItemWaveLength = mRadius *2;//一段波浪的长度mPathCircle.addCircle(w/2,h/2,mRadius, Path.Direction.CW);mProgressTextSize = mRadius*0.7f;//当控件大小发生变化时,动态修改文字大小mPaintProgress.setTextSize(mProgressTextSize);mFontMetricsInt = mPaintProgress.getFontMetricsInt();mWaveHeight = mRadius/8;//当控件大小发生变化时,动态修改波浪高度invalidate();startWaveAnim();}private void startWaveAnim() {mWaveobjectAnimator = ObjectAnimator.ofFloat(this, "wave", 0, mItemWaveLength).setDuration(4000);mWaveobjectAnimator.setRepeatCount(ValueAnimator.INFINITE);mWaveobjectAnimator.setInterpolator(new LinearInterpolator());mWaveobjectAnimator.start();}/*** 设置波浪偏移量(波浪的动画效果核心是靠这个实现的)* @param wave*/public void setWave(float wave){mWave = wave;invalidate();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.save();canvas.clipPath(mPathCircle);//将画布裁剪为圆形canvas.drawColor(Color.parseColor("#3233F92B"));mPathWave.reset();mPathWaveAlpha.reset();//将波浪路径起始点移至圆形球的左侧一段波浪长度(即上下起伏为一段)的位置处mPathWave.moveTo(getWidth()/2-mRadius-mItemWaveLength+mWave,getHeight()/2+mRadius+mWaveHeight-mProgress*(mRadius*2+mWaveHeight*2));mPathWaveAlpha.moveTo(getWidth()/2-mRadius-mItemWaveLength+mWave+mItemWaveLength/8,getHeight()/2+mRadius+mWaveHeight-mProgress*(mRadius*2+mWaveHeight*2));float half = mItemWaveLength / 4;for(float x= -mItemWaveLength;x<getWidth()+mItemWaveLength;x+=mItemWaveLength){mPathWave.rQuadTo(half/2,-mWaveHeight,half,0);//贝赛尔曲线实现波浪mPathWave.rQuadTo(half/2,mWaveHeight,half,0);mPathWaveAlpha.rQuadTo(half/2,-mWaveHeight,half,0);//贝赛尔曲线实现波浪mPathWaveAlpha.rQuadTo(half/2,mWaveHeight,half,0);}mPathWave.lineTo(getWidth(),getHeight());mPathWave.lineTo(0,getHeight());mPathWave.close();//制造闭合路径mPathWaveAlpha.lineTo(getWidth(),getHeight());mPathWaveAlpha.lineTo(0,getHeight());mPathWaveAlpha.close();//制造闭合路径mPaintWavw.setColor(Color.parseColor("#7a33F92B"));//设置后面的波浪为半透明canvas.drawPath(mPathWaveAlpha, mPaintWavw);mPaintWavw.setColor(Color.parseColor("#33F92B"));//设置前面的波浪为不透明canvas.drawPath(mPathWave, mPaintWavw);canvas.drawText((int)(mProgress*100)+"%",getWidth()/2,getHeight()/2+((mFontMetricsInt.bottom-mFontMetricsInt.top)/2-mFontMetricsInt.bottom),mPaintProgress);canvas.restore();}/*** 设置进度(不带动画)* @param progress*/public void setProgress(float progress){mProgress = progress;invalidate();}/*** 设置进度带动画* @param progress*/public void setProgressWithAnim(float progress){ObjectAnimator.ofFloat(this, "progress", 0, progress).setDuration(5000).start();}@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();if(mWaveobjectAnimator!=null){//当控件移除时取消动画mWaveobjectAnimator.cancel();}}

使用方法:

这里只有两个方法:

setProgress(float progress):设置进度(不加上升动画)
setProgressWithAnim(float progress):设置进度(加上升动画)

项目源码:

https: //github.com/myml666/WaveDemo

Android自定义View实现炫酷的加速球效果相关推荐

  1. android炫酷的自定义view,Android自定义View实现炫酷进度条

    本文实例为大家分享了Android实现炫酷进度条的具体代码,供大家参考,具体内容如下 下面我们来实现如下效果: 第一步:创建attrs文件夹,自定义属性: 第二步:自定义View: /** * Cre ...

  2. android自定义Drawable实现炫酷UI-锦鲤游泳效果

    一.实现效果: 当点击屏幕的时候,屏幕中的锦鲤会身体摆动并且游到屏幕点击处,如下图: 效果分析: 1.小鱼的身体各个部件都是简单的半透明几何图形. 2.各个部件都可以活动. 3.从头到尾方向的部件摆动 ...

  3. 自定义 View 之炫酷的成绩展示界面

    作者 | Android_gen 地址 | http://www.jianshu.com/p/03022c1306fb 声明 | 本文是 Android_gen 原创,已获授权发布,未经原作者允许请勿 ...

  4. Android自定义View分享——仿网易云音乐留声机效果

    写在前面 这是笔者自学习自定义View以来,分享的第五篇效果,之前分享过一篇动态时钟效果的自定义View,如果有兴趣的可以看看: Android自定义View分享--一个时钟 之前的博客笔者一般都会说 ...

  5. android的动态tab,Android自定义view仿QQ的Tab按钮动画效果(示例代码)

    话不多说 先上效果图 实现其实很简单,先用两张图 一张是背景的图,一张是笑脸的图片,笑脸的图片是白色,可能看不出来.实现思路:主要是再触摸view的时候同时移动这两个图片,但是移动的距离不一样,造成的 ...

  6. android 动态进度条,Android实用view系列------炫酷的进度条

    不知不觉距离上次写文章已经过去大半个月了,原本计划每周写一篇的想法在坚持几周之后最终还是被生活中各种各样的琐事打乱,无奈中夹杂这对自己的一点失望. 心痛.jpg 当初的愿望实现了吗 事到如今只好祭奠吗 ...

  7. Android自定义View实现仿QQ实现运动步数效果

    效果图: 1.attrs.xml中 <declare-styleable name="QQStepView"><attr name="outerColo ...

  8. Android自定义View之仿QQ运动步数进度效果

    文章目录 前言 先看效果图 ![在这里插入图片描述](https://img-blog.csdnimg.cn/6e4ddec17933496ea4830fa08d8ffbe5.png?x-oss-pr ...

  9. android 自定义view实现仿QQ运动步数进度效果

    最近公司在策划一个新的项目,原型还没出来,再说这公司人都要走没了,估计又要找工作了,所以必须要学习,争取每个写个关于自定义view方面的,这样几个月积累下来,也能学习到东西,今天就带来简单的效果,就是 ...

最新文章

  1. Caffe + windows + python3.5安装
  2. ubuntu1804系统设置在哪里_新风净化系统的风口到底该放在哪里?
  3. 激光IMU融合——LIO-Mapping / LIOM / LINS / LIO-SAM算法解析
  4. 数据结构 - 栈(数组模拟栈操作)
  5. 真正无人驾驶有望在美国全境普及?美交通部准备修改安全法规
  6. 1015 德才论 (25 分)—PAT (Basic Level) Practice (中文)
  7. face_recognition基础接口
  8. 高等数学-第一章 函数 极限 连续
  9. 手把手教你win10下lex与yacc的安装
  10. 一篇文章完全搞懂正则化(Regularization)
  11. 【VulnHub靶场】——HARRYPOTTER第一部: ARAGOG (1.0.2)
  12. java工程设计选题管理系统_基于javaee的毕设选题测试及管理系统的设计与实现 毕设.doc...
  13. Java前方交会后方交会编程_单像空间后方交会和双像解析空间后方-前方交会的算法程序实现.doc...
  14. Python自动化生成 word 文档
  15. 雷军需要讲好新故事,小米需要新风口
  16. vs code常用的插件
  17. java简单实现布谷鸟过滤器的
  18. jQuery动画+ajax
  19. nemesis什么车_英国Mazda推出RX-8 Nemesis限量特式车
  20. 黄聪:CR2格式批量转换JPG(美图看看)

热门文章

  1. python 18 章,learning_log的urls
  2. 上海亚商投顾:三大指数小幅调整 消费电子概念股全线走强
  3. Markdown入门和解决MD文件上传博客后图片无法显示问题
  4. cs231n Assignment1--机器学习基本方法与深度学习尝试
  5. 华为鸿蒙系统荣耀30s,华为鸿蒙操作系统2.0版支持的设备清单流出,荣耀30s
  6. 旅行家的预算(python)
  7. 关于 四舍六入五成双/四舍六入五留双/四舍六入五单双 等口诀的实例研究
  8. 【公告 | 阿布扎比全球市场为中东和北非地区推出加密资产框架】
  9. 问题已解决:重装系统遇到的问题(1)——重启后出现Couldn’t find NTLDR。
  10. Linux中重定向输入和输出