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

Android项目实战手把手教你画圆形水波纹loadingview

程序员文章站 2024-02-19 21:59:22
本文实例讲解的是如何画一个满满圆形水波纹loadingview,这类效果应用场景很多,比如内存占用百分比之类的,分享给大家供大家参考,具体内容如下 效果图如下: 预...

本文实例讲解的是如何画一个满满圆形水波纹loadingview,这类效果应用场景很多,比如内存占用百分比之类的,分享给大家供大家参考,具体内容如下
效果图如下:

Android项目实战手把手教你画圆形水波纹loadingview

预备的知识:

  • 1.贝塞尔曲线    如果你不了解,可以来这里进行基础知识储备:神奇的贝塞尔曲线
  • 2.paint.setxfermode()  以及porterduffxfermode

千万不要被这个b的名字吓到,不熟悉看到可能会认为很难记,其实 只要站在巨人的丁丁上 还是很简单的。
好了 废话不多说 ,跟我一步步来做一个炫酷的view吧。

首先给一些属性,在构造器里初始化(不要再ondraw new东西不要再ondraw new东西不要再ondraw new东西不要再ondraw new东西)
 

  //绘制波纹 
  private paint mwavepaint;  
  private porterduffxfermode mmode = new porterduffxfermode(porterduff.mode.xor);//设置mode 为xor 
  //绘制圆 
  private paint mcirclepaint; 
  private canvas mcanvas;//我们自己的画布 
  private bitmap mbitmap; 
  private int mwidth; 
  private int mheight; 
 
  public waveloadingview(context context) { 
    this(context,null); 
  } 
 
  public waveloadingview(context context, attributeset attrs) { 
    this(context, attrs,0); 
  } 
 
  public waveloadingview(context context, attributeset attrs, int defstyleattr) { 
    super(context, attrs, defstyleattr); 
 
    mwavepaint = new paint(); 
    mwavepaint.setcolor(color.parsecolor("#33b5e5")); 
    mcirclepaint = new paint(); 
    mcirclepaint.setcolor(color.parsecolor("#99cc00")); 
     
 
  } 
  @override 
  protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { 
    int widthsize = measurespec.getsize(widthmeasurespec); 
    int widthmode = measurespec.getmode(widthmeasurespec); 
    int heightsize = measurespec.getsize(heightmeasurespec); 
    int heightmode = measurespec.getmode(heightmeasurespec); 
    if (widthmode == measurespec.exactly) { 
      mwidth = widthsize; 
    } 
 
 
    if (heightmode == measurespec.exactly) { 
      mheight = heightsize; 
    } 
    setmeasureddimension(mwidth, mheight); 
    mbitmap = bitmap.createbitmap(300,300, bitmap.config.argb_8888); //生成一个bitmap 
    mcanvas = new canvas(mbitmap);//讲bitmp放在我们自己的画布上,实际上mcanvas.draw的时候 改变的是这个bitmap对象 
  } 
   

然后,我们给他绘制一点东西,用来介绍porterduffxfermode

@override 
  protected void ondraw(canvas canvas) { 
    mcanvas.drawcircle(100,100,50,mcirclepaint); 
 
    mcanvas.drawrect(100,100,200,200,mwavepaint); 
    canvas.drawbitmap(mbitmap,0,0,null); 
    super.ondraw(canvas); 
  } 

嗯,可以看到 是我们现在自己的画布上铺了一个bitmap(这里可以理解canvas为桌子  bitmap为画纸,我们在bimap上画画), 然后在bitmap上画了 一个圆,和一个矩形。最后把我们的mbitmap画到系统的画布上(显示到屏幕上),得到了以下效果。

然后我们用setxfermode()方法给他设置一个mode,这里设置xor。

Android项目实战手把手教你画圆形水波纹loadingview

可以发现! 相交的地方消失了! 是不是很神奇。
在改一个mode 试试

private porterduffxfermode mmode = new porterduffxfermode(porterduff.mode.dst_over); 

Android项目实战手把手教你画圆形水波纹loadingview

可以看到 圆形跑到了矩形上面来。  然后巨人给我们总结各个模式如了下图,这里给一个说明dst为先画的 src为后画的:.

Android项目实战手把手教你画圆形水波纹loadingview

大家可以根据这个规律试一下。

现在,我们把圆和矩形重叠。模式去掉。

protected void ondraw(canvas canvas) { 
 
    //dst 
    mcanvas.drawcircle(150,150,50,mcirclepaint); 
 
/    mwavepaint.setxfermode(mmode); 
    //src 
    mcanvas.drawrect(100,100,200,200,mwavepaint); 
    canvas.drawbitmap(mbitmap,0,0,null); 
    super.ondraw(canvas); 
  } 

我的圆怎么没了。。  其实圆是被覆盖掉了。 然后我们想实现一个效果,就是在圆的范围内,显示矩形的内容,该怎么做呢。自己照着图找找吧哈哈。

我们要实现的是一个圆形的水波纹那种loadingview。。首要就是实现这个水波纹。
这时候贝塞尔曲线就派上用场了。这里采用三阶贝塞尔, 不停地改变x 模拟水波效果。

 if (x > 50) { 
      isleft = true; 
    } else if (x < 0) { 
      isleft = false; 
    } 
<span style="white-space:pre">    </span>if (y > -50) { //大于-50是因为辅助点是50 为了让他充满整个屏幕 
      y--; 
    }    if (isleft) { 
      x = x - 1; 
    } else { 
      x = x + 1; 
    } 
    mpath.reset(); 
    mpath.moveto(0, y); 
    mpath.cubicto(100 + x*2, 50 + y, 100 + x*2, y-50, mwidth, y);//前两个参数是辅助点 
    mpath.lineto(mwidth, mheight);//充满整个画布 
    mpath.lineto(0, mheight);//充满整个画布 
    mpath.close(); 

之后用mcanvas来绘制这个bitmap,要注意的是 绘制之前要清空mbitmap,不然path会重叠

mbitmap.erasecolor(color.parsecolor("#00000000")); 
 
//dst 
 mcanvas.drawpath(mpath, mpaint); 

canvas.drawbitmap(mbitmap, 0, 0, null); 
 
 
    postinvalidatedelayed(10); 

 哈,水波效果出来了。   接着想办法让他画到一个圆形中。 首先绘制一个圆

mcanvas.drawcircle(mwidth / 2, mheight / 2, mwidth / 2, msrcpaint); 

现在让我们回到刚才的问题,如何在dst的范围内绘制src呢。。。答案是。。src_in 你找对了吗。添加模式

//dst 
   mcanvas.drawcircle(mwidth / 2, mheight / 2, mwidth / 2, msrcpaint); 
 
   mpaint.setxfermode(mmode); 
   //src 
   mcanvas.drawpath(mpath, mpaint); 
 
   canvas.drawbitmap(mbitmap, 0, 0, null); 

是不是有点感觉了。如果不这样做 就需要考虑好多问题。动态计算沿着圆弧x,y坐标  计算arcto的范围。

完善一下,添加一个percent来代表进度,让y来根据percent动态改变
y = (int) ((1-mpercent /100f) *mheight); 

添加setpercent方法

public void setpercent(int percent){ 
    mpercent = percent; 
  } 

画上百分比的文字。

string str = mpercent + "%"; 
    float txtlength = mtextpaint.measuretext(str); 
    canvas.drawtext(mpercent + "%", mwidth / 2-txtlength/2, mheight / 2, mtextpaint); 

然后配合seekbar,最后改改字体大小  画笔透明度。 添加个背景图 就成了效果图上的效果。

是不是很有趣,大家可以动手实现一下!