热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android自定义WaveView实现波浪进度效果

最近注意到百度外卖以及淘宝个人中心,都用到了类似水波起伏的效果,于是就参照网上的资料然后自己整改,自定义了一个waveView来实现这个效果,文中给出来详细的实现原理及实例代码,有需要的朋友们可以参考借鉴,下面来一起看看吧。

实现原理

首先就是自定义个WaveView 继承View,然后再WaveView 内部实现代码逻辑:

      ① 水波就波嘛? sin函数? 贝塞尔曲线? 都行,这里就用二阶贝塞 尔曲线去画吧

      ② 波要动嘛,怎么动呢?线程? 好吧 这里用了个Handler。

      ③绘制波首先要找点,那么在onMeasure()里找出需要的点咯,这里就暂时展示一个波段吧,一个波长移动左边不就没了?OK 那就两个波吧,吼吼,两个波(猥琐男潜质表露无遗啊)。接下来就是Handler 结合 onDraw()绘制。OK,那就先看我Word绘制的粗瘪的波动图,请看VCR,oh,no... gif

意思就是波平移一个波长之后回到初始位置继续平移循环。

好吧,有人说了,这么简单的逻辑你要啰嗦那么多???

好吧,我承认,我有唐僧的潜质。。。

闲话就不说了,先上

效果图


示例代码如下

调用的Activity

 * Created by LiuDong on 2016/12/22.
 * Email:15002102128@126.com
 */

public class WaveActivity extends Activity {
 LD_WaveView waveView;//方形
 LD_WaveView waveCircleView;//圆形
 private int progrees=0;//进度
 private Handler mHandler=new Handler(){
  @Override
  public void handleMessage(Message msg) {
   if (progrees==100) progrees=0;
   Log.i("progress",progrees+"");
   waveView.setmProgress(progrees++);
   waveCircleView.setmProgress(progrees++);
   mHandler.sendEmptyMessageDelayed(0,100);
  }
 };
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_wave);
  waveView= (LD_WaveView) findViewById(R.id.waveView);
  waveCircleView= (LD_WaveView) findViewById(R.id.waveViewCircle);
  mHandler.sendEmptyMessageDelayed(0,10);
 }
}

xml布局

<&#63;xml version="1.0" encoding="utf-8"&#63;>

 
 

自定义WaveView

/**
 * Created by LiuDong on 2016/12/23.
 * Email:15002102128@126.com
 */

public class LD_WaveView extends View {

 private int mProgress;//进度
 private int mTimeStep = 10;//时间间隔
 private int mSpeed = 5;//波单次移动的距离
 private int mViewHeight;//视图宽高
 private int mViewWidth;//视图宽度
 private int mLevelLine;// 基准线


 private int mWaveLength;//波长 暂定view宽度为一个波长
 private int mStrokeWidth;//园的线宽
 private RectF rectF;//圆环区域
 private int mWaveHeight;//波峰高度
 private int mLeftWaveMoveLength;//波平移的距离,用来控制波的起点位置
 private int mWaveColor;//波的颜色
 private Paint mPaint;//画笔
 private Paint mCirclePaint;//圆环画笔
 private Paint mBorderPaint;//边界画笔
 private int mBorderWidth=4;//边界宽度
 private Paint mTextPaint;//文字画笔
 private Path mPath;//绘画线
 private List mPoints;//点的集合
 private boolean isMeasure = false;//是否已测量过
 private boolean isCircle=false;//是否圆形默认false,可属性代码设置
 //处理消息
 private Handler handler = new Handler() {
  @Override
  public void handleMessage(Message msg) {

   initWaveMove();
  }
 };

 /**
  * 初始化波的移动
  */
 private void initWaveMove(){
  mLeftWaveMoveLength+=mSpeed;//波向右移动距离增加mSpeed;
  if (mLeftWaveMoveLength>=mWaveLength){//当增加到一个波长时回复到0
   mLeftWaveMoveLength=0;
  }
  invalidate();

 }
 public LD_WaveView(Context context) {
  this(context, null);
 }

 public LD_WaveView(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
 }

 public LD_WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);

  getAttr(context, attrs, defStyleAttr);
  init();

 }

 /**
  * 初始化画笔
  */
 private void init() {
  mPoints = new ArrayList();
  //波浪轨迹画笔
  mPaint = new Paint();
  mPaint.setAntiAlias(true);
  mPaint.setColor(mWaveColor);
  mPaint.setStyle(Paint.Style.FILL_AND_STROKE);


  mPath = new Path();


  //文字画笔
  mTextPaint=new Paint();
  mTextPaint.setColor(Color.RED);
  mTextPaint.setTextAlign(Paint.Align.CENTER);
  mTextPaint.setTextSize(48);


  //圆环画笔
  mCirclePaint=new Paint();
  mCirclePaint.setAntiAlias(true);
  mCirclePaint.setColor(Color.WHITE);
  mCirclePaint.setStyle(Paint.Style.STROKE);
  //边界线画笔
  mBorderPaint=new Paint();
  mBorderPaint.setAntiAlias(true);
  mBorderPaint.setColor(mWaveColor);
  mBorderPaint.setStrokeWidth(mBorderWidth);
  mBorderPaint.setStyle(Paint.Style.STROKE);


 }

 /**
  * 获取自定义的属性值
  *
  * @param attrs
  */
 private void getAttr(Context context, AttributeSet attrs, int defStyle) {

  TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LD_WaveView, defStyle, 0);

  mWaveColor = a.getColor(R.styleable.LD_WaveView_wave_color, Color.RED);
  isCircle=a.getBoolean(R.styleable.LD_WaveView_wave_circle,false);
  a.recycle();

 }


 /**
  *
  * @param widthMeasureSpec
  * @param heightMeasureSpec
  */
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  if (!isMeasure&&Math.abs(getMeasuredHeight()-getMeasuredWidth())<50) {//只计算一次就够了 ,relativelayout的时候要绘制两次 加个宽高判断
   mViewHeight = getMeasuredHeight();
   mViewWidth = getMeasuredWidth();
   mLevelLine = mViewHeight; //初始化波的准位线  起始位视图最底部
   {
    mLevelLine = mViewHeight * (100-mProgress) / 100;
    if (mLevelLine <0) mLevelLine = 0;
   }
   //计算波峰值
   mWaveHeight = mViewHeight / 20;//波峰暂定为view高度的1/20,如果需要设置 可设置set方法赋值;
   mWaveLength = getMeasuredWidth();

   //计算所有的点 这里取宽度为整个波长 往左再延伸一个波长 两个波长则需要9个点
   for (int i = 0; i <9; i++) {
    int y = 0;
    switch (i % 4) {
     case 0:
      y = mViewHeight;
      break;
     case 1:
      y =mViewHeight+ mWaveHeight;
      break;
     case 2:
      y = mViewHeight;
      break;
     case 3:
      y = mViewHeight-mWaveHeight;
      break;
    }
    Point point = new Point(-mWaveLength + i * mWaveLength / 4, y);
    mPoints.add(point);
   }
   /**
    * 计算圆环宽度
    */
   int mIncircleRadius=mViewHeight=50)//如果进度达到50 颜色变为白色,没办法啊,进度在中间 不变颜色看不到
   mTextPaint.setColor(Color.WHITE);
  else
  mTextPaint.setColor(mWaveColor);
  canvas.drawText(progress,0,progress.length(),mViewWidth/2,mViewHeight/2+textHeight/2,mTextPaint);

  if (isCircle) {
   /**
    * 绘制圆环
    */

   canvas.drawArc(rectF, 0, 360, true, mCirclePaint);
   Paint circlePaint = new Paint();
   circlePaint.setStrokeWidth(5);
   circlePaint.setColor(Color.WHITE);
   circlePaint.setAntiAlias(true);
   circlePaint.setStyle(Paint.Style.STROKE);
   canvas.drawCircle(mViewWidth / 2, mViewHeight / 2, mViewHeight / 2, circlePaint);
   /**
    * 绘制边界
    */

   mBorderPaint.setStrokeWidth(mBorderWidth/2);
  canvas.drawCircle(mViewWidth/2,mViewHeight/2,mViewHeight/2-mBorderWidth/2,mBorderPaint);
  }else {
   /**
    * 绘制矩形边框
    */
   canvas.drawRect(0,0,mViewWidth,mViewHeight,mBorderPaint);
  }
  //
  handler.sendEmptyMessageDelayed(0,mTimeStep);
 }

 /**
  * 设置进度 基准线
  * @param mProgress
  */
 public void setmProgress(int mProgress) {
  this.mProgress = mProgress;
  mLevelLine=(100-mProgress)*mViewHeight/100;
 }

 /**
  * 设置是否为圆形
  * @param circle
  */
 public void setCircle(boolean circle) {
  isCircle = circle;
 }
}

自定义属性

<&#63;xml version="1.0" encoding="utf-8"&#63;>

 
  
  
 

总结

好了,以上就是这篇文章的全部内容了,代码里备注应该还算比较清楚了,希望能对一些人有一些帮助,瑕疵不足之处欢迎指正,或者有好的建议。也可以留言交流。


推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 在计算机技术的学习道路上,51CTO学院以其专业性和专注度给我留下了深刻印象。从2012年接触计算机到2014年开始系统学习网络技术和安全领域,51CTO学院始终是我信赖的学习平台。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 本文介绍了如何使用jQuery根据元素的类型(如复选框)和标签名(如段落)来获取DOM对象。这有助于更高效地操作网页中的特定元素。 ... [详细]
  • 本文将详细介绍如何使用剪映应用中的镜像功能,帮助用户轻松实现视频的镜像效果。通过简单的步骤,您可以快速掌握这一实用技巧。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 本文介绍如何在 Xcode 中使用快捷键和菜单命令对多行代码进行缩进,包括右缩进和左缩进的具体操作方法。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • 在Linux系统中配置并启动ActiveMQ
    本文详细介绍了如何在Linux环境中安装和配置ActiveMQ,包括端口开放及防火墙设置。通过本文,您可以掌握完整的ActiveMQ部署流程,确保其在网络环境中正常运行。 ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
  • 如何在WPS Office for Mac中调整Word文档的文字排列方向
    本文将详细介绍如何使用最新版WPS Office for Mac调整Word文档中的文字排列方向。通过这些步骤,用户可以轻松更改文本的水平或垂直排列方式,以满足不同的排版需求。 ... [详细]
  • 本文总结了在使用Ionic 5进行Android平台APK打包时遇到的问题,特别是针对QRScanner插件的改造。通过详细分析和提供具体的解决方法,帮助开发者顺利打包并优化应用性能。 ... [详细]
  • 理解存储器的层次结构有助于程序员优化程序性能,通过合理安排数据在不同层级的存储位置,提升CPU的数据访问速度。本文详细探讨了静态随机访问存储器(SRAM)和动态随机访问存储器(DRAM)的工作原理及其应用场景,并介绍了存储器模块中的数据存取过程及局部性原理。 ... [详细]
  • 360SRC安全应急响应:从漏洞提交到修复的全过程
    本文详细介绍了360SRC平台处理一起关键安全事件的过程,涵盖从漏洞提交、验证、排查到最终修复的各个环节。通过这一案例,展示了360在安全应急响应方面的专业能力和严谨态度。 ... [详细]
  • 几何画板展示电场线与等势面的交互关系
    几何画板是一款功能强大的物理教学软件,具备丰富的绘图和度量工具。它不仅能够模拟物理实验过程,还能通过定量分析揭示物理现象背后的规律,尤其适用于难以在实际实验中展示的内容。本文将介绍如何使用几何画板演示电场线与等势面之间的关系。 ... [详细]
author-avatar
球球爱生活0423
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有