欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义WaveProgressView实现水波纹加载需求

程序员文章站 2023-12-19 19:54:34
先看效果图:   你可以定义成你项目的logo图片,可以设置水波颜色、波长、波宽、字体大小、颜色、进度条的最大值,当前进度值,还可以设置波纹震动的快慢。当设置一个进度...

先看效果图:

Android自定义WaveProgressView实现水波纹加载需求

  你可以定义成你项目的logo图片,可以设置水波颜色、波长、波宽、字体大小、颜色、进度条的最大值,当前进度值,还可以设置波纹震动的快慢。当设置一个进度不变的时候,打开时还有一个动画填满的效果(比如第二个流量显示,这里图片没有截出这个效果)。

  源码地址

1. 如何使用

1.1 在布局文件中

  添加自定义控件:

<cn.fanrunqi.waveprogressview.waveprogressview
 android:id="@+id/waveprogressbar"
 android:background="@drawable/circle"
 <!--android:background="@drawable/bg_a"-->
 android:layout_width="130dp"
 android:layout_height="130dp" />

  说明,这里的android:background定义的是控件的形状,比如上面的圆形和美女,你可用shape.xml定义形状图片。

比如,这是一个圆

<?xml version="1.0" encoding="utf-8"?>
<shape
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:shape="oval">
 <solid android:color="#dddddd"/>
 <size android:width="150dp"
 android:height="150dp"/>
</shape>

也可以直接给android:background设置一张图片,比如:

Android自定义WaveProgressView实现水波纹加载需求 

这里注意透明像素,还有为了图片缩放的时候不变形,建议背景(不管是图片还是图形)为正方形。

1.2 在代码中

你可以选择进行如下设置:

//设置当前进度值和当前显示的文字
waveprogressbar.setcurrent(int currentprogress,string currenttext); // 77, "788m/1024m"
//设置进度条的最大值
waveprogressbar.setmaxprogress(int maxprogress);
//设置显示文字的大小和颜色
waveprogressbar.settext(string mtextcolor,int mtextsize);//"#ffff00", 41
//设置水波的颜色
waveprogressbar.setwavecolor(string mwavecolor); //"#5b9ef4"
//设置波浪的高度和波浪的宽度(均为一个波峰的大小)
waveprogressbar.setwave(float mwavehight,float mwavewidth);
//设置波浪的上下震动的速度(这里注意值越大,震动的越小)
waveprogressbar.setmwavespeed(int mwavespeed);//the larger the value, the slower the vibration

2. 代码实现

  这里实现主要用到的知识有 自定义view、porterduffxfermode和二阶贝塞尔曲线,不太清楚的可以在我博客找找,都有的。   
  首先自定义waveprogressview继承view,在构造函数中获取布局文件中设置的背景,同时设置一个画波浪的画笔和画文字的画笔。  

private void init() {
 /**
 * 获得背景
 */
 if(null==getbackground()){
 throw new illegalargumentexception(string.format("background is null."));
 }else{
 backgroundbitmap = getbitmapfromdrawable(getbackground());
 }
 /**
 * 波浪画笔
 */
 mpath = new path();
 mpathpaint = new paint();
 mpathpaint.setantialias(true);
 mpathpaint.setstyle(paint.style.fill);
 /**
 * 进度画笔
 */
 mtextpaint = new paint();
 mtextpaint.setantialias(true);
 mtextpaint.settextalign(paint.align.center);
     //开始不断自我绘制,让波浪动起来
 handler.sendemptymessagedelayed(invalidate,100);
 }

  复写ondraw方法,先把波浪画在画布上,然后画背景(给背景画笔设置porterduff.mode.dst_atop模式:取上层非交集部分与下层交集部分 )。当然也可以是porterduff.mode.src_atop,主要取决于你画的先后顺序。最后把文字画上去,形成一个最终bitmap,最后把这个bitmap画到ondraw的参数canvas上。

 paint paint = new paint();
 paint.setantialias(true);
 bitmap finalbmp = bitmap.createbitmap(width,height, bitmap.config.argb_8888);
 /**
 * 产生一个同样大小的画布
 */
 canvas canvas = new canvas(finalbmp);
 /**
 * 绘制波浪
 */
 float curmidy = height*(maxprogress-currentprogress)/maxprogress;
 if(cury>curmidy){
 cury = cury - (cury-curmidy)/10;
 }
 mpath.reset();
 mpath.moveto(0-distance,cury);

 int wavenum = width/((int)mwavehalfwidth*4)+1;
 int multiplier = 0;
 for(int i =0;i<wavenum;i++){
 mpath.quadto(mwavehalfwidth*(multiplier+1)-distance,cury-mwavehight,mwavehalfwidth*(multiplier+2)-distance,cury);
 mpath.quadto(mwavehalfwidth*(multiplier+3)-distance,cury+mwavehight,mwavehalfwidth*(multiplier+4)-distance,cury);
 multiplier+=4;
 }
 distance +=mwavehalfwidth/mwavespeed;
 distance = distance%(mwavehalfwidth*4);

 mpath.lineto(width,height);
 mpath.lineto(0,height);
 mpath.close();
 canvas.drawpath(mpath, mpathpaint);
 /**
 * 对图片给进行缩放
 */
 int min = math.min(width,height);
 backgroundbitmap = bitmap.createscaledbitmap(backgroundbitmap,min,min,false);
 /**
 * 使用dst_atop,取上层非交集部分与下层交集部分 。
 */
 paint.setxfermode(new porterduffxfermode(porterduff.mode.dst_atop));
 /**
 * 绘制图片
 */
 canvas.drawbitmap(backgroundbitmap,0,0,paint);
 /**
 * 绘制进度文字
 */
 canvas.drawtext(currenttext, width/2, height/2, mtextpaint);
 return finalbmp;

  这里的cury是上次波浪中线的y轴坐标,curmidy 是当前的y轴坐标,每次波浪上升的时候为了不产生卡顿效果,把这1/100的上升分为10次来绘制。
  distance是x轴的偏移量,为了使水波动起来,每次绘制时都要向左进行一段偏移。 

distance +=mwavehalfwidth/mwavespeed;
distance = distance%(mwavehalfwidth*4);

  每次偏移距离为 半波宽度/波浪震动速度,因为一个波是4个半波宽度形成一个循环,然后又回到最开始x位置开始循环位移。
  根据view的宽度计算出一共要绘制多少个波形出来,同时多加一个波为了向左平移。

int wavenum = width/((int)mwavehalfwidth*4)+1;
 int multiplier = 0;
 for(int i =0;i<wavenum;i++){
  mpath.quadto(mwavehalfwidth*(multiplier+1)-distance,cury-mwavehight,mwavehalfwidth*(multiplier+2)-distance,cury);
  mpath.quadto(mwavehalfwidth*(multiplier+3)-distance,cury+mwavehight,mwavehalfwidth*(multiplier+4)-distance,cury);
  multiplier+=4;
 }

  每次绘制以波形的左边点、波形的右边点、view的左下角、view的右下角、形成一个图片把它绘制到内存中新建的和view同大小的canvas上。 

mpath.reset();
mpath.moveto(0-distance,cury);

mpath.lineto(width,height);
mpath.lineto(0,height);
mpath.close();
canvas.drawpath(mpath, mpathpaint);

  先对背景图形进行缩放再绘制到canvas上,这里的缩放是按最小边进行缩放。

int min = math.min(width,height);
backgroundbitmap = bitmap.createscaledbitmap(backgroundbitmap,min,min,false);

最后把文字绘制上去,注意我们在初始化中设置了画笔,为了能通过代码设置文字的颜色,要把设置文字画笔颜色和大小放在ondraw方法中。

mpathpaint.setcolor(color.parsecolor(mwavecolor));
mtextpaint.setcolor(color.parsecolor(mtextcolor));
mtextpaint.settextsize(mtextsize);
canvas.drawtext(currenttext, width/2, height/2, mtextpaint);

为了使波浪动起来,使用handler循环调用invalidate刷新界面。同时应该在构造函数打开handler循环。

private static final int invalidate = 0x777;
 private handler handler = new handler() {
 @override
 public void handlemessage(message msg) {
  super.handlemessage(msg);
  switch (msg.what) {
  case invalidate:
   invalidate();
   sendemptymessagedelayed(invalidate,refreshgap);
   break;
  }
 }
 };

最后就是一些相关属性设置的函数。

 /**
 * @param currentprogress 当前进度
 * @param currenttext 当前显示的进度文字
 */
 public void setcurrent(int currentprogress,string currenttext) {
 this.currentprogress = currentprogress;
 this.currenttext = currenttext;
 }

 /**
 * @param maxprogress 设置进度条的最大值,默认100
 */
 public void setmaxprogress(int maxprogress){
 this.maxprogress = maxprogress;
 }

 /**
 * @param mtextcolor 文字的颜色
 * @param mtextsize 文字的大小
 */
 public void settext(string mtextcolor,int mtextsize){
 this.mtextcolor = mtextcolor;
 this.mtextsize = mtextsize;
 }
 /**
 * @param mwavehight 波峰的高度
 * @param mwavewidth 一个波峰的宽度
 */
 public void setwave(float mwavehight,float mwavewidth){
 this.mwavehight = mwavehight;
 this.mwavehalfwidth = mwavewidth/2;
 }

 /**
 * @param mwavecolor 水的颜色
 */
 public void setwavecolor(string mwavecolor){
 this.mwavecolor = mwavecolor;
 }
 /**
 * 值越大震荡的越慢
 * @param mwavespeed
 */
 public void setmwavespeed(int mwavespeed){
 this.mwavespeed = mwavespeed;
 }

实现还是比较简单的,源码和demo都在上面的地址中,如果有什么问题可以给我留言,谢谢!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

上一篇:

下一篇: