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

Android中自定义View实现圆环等待及相关的音量调节效果

程序员文章站 2024-03-01 21:20:52
圆环交替、等待效果 效果就这样,分析了一下,大概有这几个属性,两个颜色,一个速度,一个圆环的宽度。 自定view的几个步骤: 1、自定义view的属性 2、...

圆环交替、等待效果

Android中自定义View实现圆环等待及相关的音量调节效果

效果就这样,分析了一下,大概有这几个属性,两个颜色,一个速度,一个圆环的宽度。
自定view的几个步骤:
1、自定义view的属性
2、在view的构造方法中获得我们自定义的属性
3、重写onmesure 
4、重写ondraw

1、自定义属性:

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
 
  <attr name="firstcolor" format="color" /> 
  <attr name="secondcolor" format="color" /> 
  <attr name="circlewidth" format="dimension" /> 
  <attr name="speed" format="integer" /> 
 
  <declare-styleable name="customprogressbar"> 
    <attr name="firstcolor" /> 
    <attr name="secondcolor" /> 
    <attr name="circlewidth" /> 
    <attr name="speed" /> 
  </declare-styleable> 
 
</resources> 

2、在view的构造方法中获得我们自定义的属性

/** 
   * 第一圈的颜色 
   */ 
  private int mfirstcolor; 
  /** 
   * 第二圈的颜色 
   */ 
  private int msecondcolor; 
  /** 
   * 圈的宽度 
   */ 
  private int mcirclewidth; 
  /** 
   * 画笔 
   */ 
  private paint mpaint; 
  /** 
   * 当前进度 
   */ 
  private int mprogress; 
 
  /** 
   * 速度 
   */ 
  private int mspeed; 
 
  /** 
   * 是否应该开始下一个 
   */ 
  private boolean isnext = false; 
 
  public customprogressbar(context context, attributeset attrs) 
  { 
    this(context, attrs, 0); 
  } 
 
  public customprogressbar(context context) 
  { 
    this(context, null); 
  } 
 
  /** 
   * 必要的初始化,获得一些自定义的值 
   * 
   * @param context 
   * @param attrs 
   * @param defstyle 
   */ 
  public customprogressbar(context context, attributeset attrs, int defstyle) 
  { 
    super(context, attrs, defstyle); 
    typedarray a = context.gettheme().obtainstyledattributes(attrs, r.styleable.customprogressbar, defstyle, 0); 
    int n = a.getindexcount(); 
 
    for (int i = 0; i < n; i++) 
    { 
      int attr = a.getindex(i); 
      switch (attr) 
      { 
      case r.styleable.customprogressbar_firstcolor: 
        mfirstcolor = a.getcolor(attr, color.green); 
        break; 
      case r.styleable.customprogressbar_secondcolor: 
        msecondcolor = a.getcolor(attr, color.red); 
        break; 
      case r.styleable.customprogressbar_circlewidth: 
        mcirclewidth = a.getdimensionpixelsize(attr, (int) typedvalue.applydimension( 
            typedvalue.complex_unit_px, 20, getresources().getdisplaymetrics())); 
        break; 
      case r.styleable.customprogressbar_speed: 
        mspeed = a.getint(attr, 20);// 默认20 
        break; 
      } 
    } 
    a.recycle(); 
    mpaint = new paint(); 
    // 绘图线程 
    new thread() 
    { 
      public void run() 
      { 
        while (true) 
        { 
          mprogress++; 
          if (mprogress == 360) 
          { 
            mprogress = 0; 
            if (!isnext) 
              isnext = true; 
            else 
              isnext = false; 
          } 
          postinvalidate(); 
          try 
          { 
            thread.sleep(mspeed); 
          } catch (interruptedexception e) 
          { 
            e.printstacktrace(); 
          } 
        } 
      }; 
    }.start(); 
 
  } 

3、直接重写ondraw,这不需要重写onmeasure

@override 
  protected void ondraw(canvas canvas) 
  { 
 
    int centre = getwidth() / 2; // 获取圆心的x坐标 
    int radius = centre - mcirclewidth / 2;// 半径 
    mpaint.setstrokewidth(mcirclewidth); // 设置圆环的宽度 
    mpaint.setantialias(true); // 消除锯齿 
    mpaint.setstyle(paint.style.stroke); // 设置空心 
    rectf oval = new rectf(centre - radius, centre - radius, centre + radius, centre + radius); // 用于定义的圆弧的形状和大小的界限 
    if (!isnext) 
    {// 第一颜色的圈完整,第二颜色跑 
      mpaint.setcolor(mfirstcolor); // 设置圆环的颜色 
      canvas.drawcircle(centre, centre, radius, mpaint); // 画出圆环 
      mpaint.setcolor(msecondcolor); // 设置圆环的颜色 
      canvas.drawarc(oval, -90, mprogress, false, mpaint); // 根据进度画圆弧 
    } else 
    { 
      mpaint.setcolor(msecondcolor); // 设置圆环的颜色 
      canvas.drawcircle(centre, centre, radius, mpaint); // 画出圆环 
      mpaint.setcolor(mfirstcolor); // 设置圆环的颜色 
      canvas.drawarc(oval, -90, mprogress, false, mpaint); // 根据进度画圆弧 
    } 
 
  } 

大功完成了,当然了,唯一比较纠结的地方就是两个颜色何时切换,如何切换,我采用上面的办法,你也可以自己想想怎么实现。

视频音量调控

Android中自定义View实现圆环等待及相关的音量调节效果

这样一个效果使用自定义view来实现的话和圆环的思路差不多,所以我们一起来看:
1、先分许需要的属性,两个小块的颜色、一张中间的图片、间隙大小、一个多少个块块。分析完毕,开始写attr.xml

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
 
  <attr name="firstcolor" format="color" /> 
  <attr name="secondcolor" format="color" /> 
  <attr name="circlewidth" format="dimension" /> 
  <attr name="dotcount" format="integer" /> 
  <attr name="splitsize" format="integer" /> 
  <attr name="bg" format="reference"></attr> 
 
  <declare-styleable name="customvolumcontrolbar"> 
    <attr name="firstcolor" /> 
    <attr name="secondcolor" /> 
    <attr name="circlewidth" /> 
    <attr name="dotcount" /> 
    <attr name="splitsize" /> 
    <attr name="bg" /> 
  </declare-styleable> 
 
</resources> 

2、在构造中获取这些属性:

/** 
   * 第一圈的颜色 
   */ 
  private int mfirstcolor; 
 
  /** 
   * 第二圈的颜色 
   */ 
  private int msecondcolor; 
  /** 
   * 圈的宽度 
   */ 
  private int mcirclewidth; 
  /** 
   * 画笔 
   */ 
  private paint mpaint; 
  /** 
   * 当前进度 
   */ 
  private int mcurrentcount = 3; 
 
  /** 
   * 中间的图片 
   */ 
  private bitmap mimage; 
  /** 
   * 每个块块间的间隙 
   */ 
  private int msplitsize; 
  /** 
   * 个数 
   */ 
  private int mcount; 
 
  private rect mrect; 
 
  public customvolumcontrolbar(context context, attributeset attrs) 
  { 
    this(context, attrs, 0); 
  } 
 
  public customvolumcontrolbar(context context) 
  { 
    this(context, null); 
  } 
 
  /** 
   * 必要的初始化,获得一些自定义的值 
   * 
   * @param context 
   * @param attrs 
   * @param defstyle 
   */ 
  public customvolumcontrolbar(context context, attributeset attrs, int defstyle) 
  { 
    super(context, attrs, defstyle); 
    typedarray a = context.gettheme().obtainstyledattributes(attrs, r.styleable.customvolumcontrolbar, defstyle, 0); 
    int n = a.getindexcount(); 
 
    for (int i = 0; i < n; i++) 
    { 
      int attr = a.getindex(i); 
      switch (attr) 
      { 
      case r.styleable.customvolumcontrolbar_firstcolor: 
        mfirstcolor = a.getcolor(attr, color.green); 
        break; 
      case r.styleable.customvolumcontrolbar_secondcolor: 
        msecondcolor = a.getcolor(attr, color.cyan); 
        break; 
      case r.styleable.customvolumcontrolbar_bg: 
        mimage = bitmapfactory.decoderesource(getresources(), a.getresourceid(attr, 0)); 
        break; 
      case r.styleable.customvolumcontrolbar_circlewidth: 
        mcirclewidth = a.getdimensionpixelsize(attr, (int) typedvalue.applydimension( 
            typedvalue.complex_unit_px, 20, getresources().getdisplaymetrics())); 
        break; 
      case r.styleable.customvolumcontrolbar_dotcount: 
        mcount = a.getint(attr, 20);// 默认20 
        break; 
      case r.styleable.customvolumcontrolbar_splitsize: 
        msplitsize = a.getint(attr, 20); 
        break; 
      } 
    } 
    a.recycle(); 
    mpaint = new paint(); 
    mrect = new rect(); 
  } 

3、重写ondraw

@override 
  protected void ondraw(canvas canvas) 
  { 
    mpaint.setantialias(true); // 消除锯齿 
    mpaint.setstrokewidth(mcirclewidth); // 设置圆环的宽度 
    mpaint.setstrokecap(paint.cap.round); // 定义线段断电形状为圆头 
    mpaint.setantialias(true); // 消除锯齿 
    mpaint.setstyle(paint.style.stroke); // 设置空心 
    int centre = getwidth() / 2; // 获取圆心的x坐标 
    int radius = centre - mcirclewidth / 2;// 半径 
    /** 
     * 画块块去 
     */ 
    drawoval(canvas, centre, radius); 
 
    /** 
     * 计算内切正方形的位置 
     */ 
    int relradius = radius - mcirclewidth / 2;// 获得内圆的半径 
    /** 
     * 内切正方形的距离顶部 = mcirclewidth + relradius - √2 / 2 
     */ 
    mrect.left = (int) (relradius - math.sqrt(2) * 1.0f / 2 * relradius) + mcirclewidth; 
    /** 
     * 内切正方形的距离左边 = mcirclewidth + relradius - √2 / 2 
     */ 
    mrect.top = (int) (relradius - math.sqrt(2) * 1.0f / 2 * relradius) + mcirclewidth; 
    mrect.bottom = (int) (mrect.left + math.sqrt(2) * relradius); 
    mrect.right = (int) (mrect.left + math.sqrt(2) * relradius); 
 
    /** 
     * 如果图片比较小,那么根据图片的尺寸放置到正中心 
     */ 
    if (mimage.getwidth() < math.sqrt(2) * relradius) 
    { 
      mrect.left = (int) (mrect.left + math.sqrt(2) * relradius * 1.0f / 2 - mimage.getwidth() * 1.0f / 2); 
      mrect.top = (int) (mrect.top + math.sqrt(2) * relradius * 1.0f / 2 - mimage.getheight() * 1.0f / 2); 
      mrect.right = (int) (mrect.left + mimage.getwidth()); 
      mrect.bottom = (int) (mrect.top + mimage.getheight()); 
 
    } 
    // 绘图 
    canvas.drawbitmap(mimage, null, mrect, mpaint); 
  } 
 
  /** 
   * 根据参数画出每个小块 
   * 
   * @param canvas 
   * @param centre 
   * @param radius 
   */ 
  private void drawoval(canvas canvas, int centre, int radius) 
  { 
    /** 
     * 根据需要画的个数以及间隙计算每个块块所占的比例*360 
     */ 
    float itemsize = (360 * 1.0f - mcount * msplitsize) / mcount; 
 
    rectf oval = new rectf(centre - radius, centre - radius, centre + radius, centre + radius); // 用于定义的圆弧的形状和大小的界限 
 
    mpaint.setcolor(mfirstcolor); // 设置圆环的颜色 
    for (int i = 0; i < mcount; i++) 
    { 
      canvas.drawarc(oval, i * (itemsize + msplitsize), itemsize, false, mpaint); // 根据进度画圆弧 
    } 
 
    mpaint.setcolor(msecondcolor); // 设置圆环的颜色 
    for (int i = 0; i < mcurrentcount; i++) 
    { 
      canvas.drawarc(oval, i * (itemsize + msplitsize), itemsize, false, mpaint); // 根据进度画圆弧 
    } 
  } 

这里需要注意下:
画块:首先根据块数量和间隙计算,每个块所占的比例。
画图:当图比较大时,直接使用该环内切正方形大小进行约束,当图片比较小时,在正中心的位置绘制。有些数学运算过程,楼主在草稿上画了一会,不复杂,大家自己画画,我就不贴草稿了。

4、添加触摸监听:

/** 
   * 当前数量+1 
   */ 
  public void up() 
  { 
    mcurrentcount++; 
    postinvalidate(); 
  } 
 
  /** 
   * 当前数量-1 
   */ 
  public void down() 
  { 
    mcurrentcount--; 
    postinvalidate(); 
  } 
 
  private int xdown, xup; 
 
  @override 
  public boolean ontouchevent(motionevent event) 
  { 
 
    switch (event.getaction()) 
    { 
    case motionevent.action_down: 
      xdown = (int) event.gety(); 
      break; 
 
    case motionevent.action_up: 
      xup = (int) event.gety(); 
      if (xup > xdown)// 下滑 
      { 
        down(); 
      } else 
      { 
        up(); 
      } 
      break; 
    } 
 
    return true; 
  } 

触摸监听也得很简单哈,基本能实现,大家也可以加个最小距离加速度什么的,都行。

最后,效果图:

Android中自定义View实现圆环等待及相关的音量调节效果