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

Android自定义环形LoadingView效果

程序员文章站 2023-08-25 13:58:15
最近项目有要用到环形的进度条,github上有一个类似的dashedcircularprogress控件,但是他画的进度是通过设置画笔的虚线效果来实现间隔的:progres...

最近项目有要用到环形的进度条,github上有一个类似的dashedcircularprogress控件,但是他画的进度是通过设置画笔的虚线效果来实现间隔的:progresspaint.setpatheffect(new dashpatheffect(new float[]{dashwith, dashspace}, dashspace));如果内层还有一层圆环,在动态设置时,内层和外层有细微的偏差.于是我在原有基础上改了一个,实现了我要的效果(设置进度时可以选择加动画或者不加动画):

Android自定义环形LoadingView效果

控件实现:

这个控件继承relativelayout,在ondraw时做了两件事:

1、先画出底部的黑色环形;
2、按照当时的进度值画出对应比例的外层绿色环形.

对外提供一个接口,回调当前进度值:

public interface onvaluechangelistener {
  void onvaluechange(float value);
}

核心绘制类:

internalcirclepainterimp2,绘制内层的黑色的环形:

/**
 * @author chuck
 */
public class internalcirclepainterimp2 implements internalcirclepainter {

  private rectf internalcircle;//画出圆弧时,圆弧的外切矩形
  private paint internalcirclepaint;
  private int color;
  private float startangle = 270f;
  int arcquantity=100;//等分(圆弧加间隔),比如arcquantity=100时,表示将有100个圆弧,和100个空白间隔
  float ratio=0.5f;//每段圆弧与圆弧加间隔之和的比例,ratio=0.5表示每个圆弧与相邻的间隔弧度比是1:1
  private int width;
  private int height;
  private int internalstrokewidth = 48;//圆环宽度

  public internalcirclepainterimp2(int color, int progressstrokewidth, int arcquantity,float ratio) {
    this.color = color;
    this.internalstrokewidth = progressstrokewidth;
    this.arcquantity = arcquantity;
    if(ratio>0&&ratio<1){
      this.ratio = ratio;
    }

    init();
  }

  private void init() {
    initexternalcirclepainter();
  }

  private void initexternalcirclepainter() {
    internalcirclepaint = new paint();
    internalcirclepaint.setantialias(true);
    internalcirclepaint.setstrokewidth(internalstrokewidth);
    internalcirclepaint.setcolor(color);
    internalcirclepaint.setstyle(paint.style.stroke);

  }

  //圆弧外切矩形
  private void initexternalcircle() {
    internalcircle = new rectf();
    float padding = internalstrokewidth * 0.5f;
    internalcircle.set(padding, padding , width - padding, height - padding);
    initexternalcirclepainter();
  }


  @override
  public void draw(canvas canvas) {

    float eachangle=360f/arcquantity;

    float eacharcangle=eachangle*ratio;

    for(int i=0;i<arcquantity*2;i++){
      if(i%2==0){//遇到偶数就画圆弧,基数则跳过
        canvas.drawarc(internalcircle, startangle+eachangle*i/2, eacharcangle, false, internalcirclepaint);
      }
      else{
        continue;
      }
    }

  }

  public void setcolor(int color) {
    this.color = color;
    internalcirclepaint.setcolor(color);
  }

  @override
  public int getcolor() {
    return color;
  }

  @override
  public void onsizechanged(int height, int width) {
    this.width = width;
    this.height = height;
    initexternalcircle();
  }
}

progresspainterimp2,绘制内层的黑色的环形:

/**
 * @author chuck
 */
public class progresspainterimp2 implements progresspainter {

  private rectf progresscircle;
  private paint progresspaint;
  private int color = color.red;
  private float startangle = 270f;
  private int internalstrokewidth = 48;
  private float min;
  private float max;
  private int width;
  private int height;

  private int currentpecent;//当前的百分比

  int arcquantity=100;//等分(圆弧加间隔),比如arcquantity=100时,表示将有100个圆弧,和100个空白间隔
  float ratio=0.5f;//每段圆弧与圆弧加间隔之和的比例,ratio=0.5表示每个圆弧与相邻的间隔弧度比是1:1

  public progresspainterimp2(int color, float min, float max, int progressstrokewidth, int arcquantity,float ratio) {
    this.color = color;
    this.min = min;
    this.max = max;
    this.internalstrokewidth = progressstrokewidth;
    this.arcquantity = arcquantity;
    this.ratio = ratio;
    init();
    log.e("progresspainterimp","构造函数执行");
  }

  private void init() {
    initinternalcirclepainter();

  }

  private void initinternalcirclepainter() {
    progresspaint = new paint();
    progresspaint.setantialias(true);
    progresspaint.setstrokewidth(internalstrokewidth);
    progresspaint.setcolor(color);
    progresspaint.setstyle(paint.style.stroke);

  }

  //初始化外切的那个矩形
  private void initinternalcircle() {
    progresscircle = new rectf();
    float padding = internalstrokewidth * 0.5f;
    progresscircle.set(padding, padding , width - padding, height - padding);

    initinternalcirclepainter();
  }

  @override
  public void draw(canvas canvas) {

    float eachangle=360f/arcquantity;

    float eacharcangle=eachangle*ratio;

    int quantity=2*arcquantity*currentpecent/100;
    for(int i=0;i<quantity;i++){
      if(i%2==0){//遇到偶数就画圆弧,基数则跳过
        canvas.drawarc(progresscircle, startangle+eachangle*i/2, eacharcangle, false, progresspaint);
      }
      else{
        continue;
      }
    }
  }

  public float getmin() {
    return min;
  }

  public void setmin(float min) {
    this.min = min;
  }

  public float getmax() {
    return max;
  }

  public void setmax(float max) {
    this.max = max;
  }

  public void setvalue(float value) {
    this.currentpecent = (int) (( 100f * value) / max);
  }

  @override
  public void onsizechanged(int height, int width) {
    log.e("progresspainterimp","onsizechanged执行");

    this.width = width;
    this.height = height;
    initinternalcircle();
  }

  public int getcolor() {
    return color;
  }

  public void setcolor(int color) {
    this.color = color;
    progresspaint.setcolor(color);
  }
}

可以自定义的属性:

<declare-styleable name="circularloadingview">
  <attr name="base_color" format="color" /> <!--内层圆环的颜色-->
  <attr name="progress_color" format="color" /><!--进度圆环的颜色-->
  <attr name="max" format="float" /><!--最小值-->
  <attr name="min" format="float" /><!--最大值-->
  <attr name="duration" format="integer" /><!--动画时长-->
  <attr name="progress_stroke_width" format="integer" /><!--圆环宽度-->

  <!--等分(圆弧加间隔),比如arcquantity=100时,表示将有100个圆弧,和100个空白间隔-->
  <attr name="argquantity" format="integer" />
  
  <!--每段圆弧与圆弧加间隔之和的比例,ratio=0.5表示每个圆弧与相邻的间隔弧度比是1:1-->
  <attr name="ratio" format="float" />
</declare-styleable>

调用:

main_activity.xml:

<?xml version="1.0" encoding="utf-8"?>
<relativelayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingbottom="@dimen/activity_vertical_margin"
  android:paddingleft="@dimen/activity_horizontal_margin"
  android:paddingright="@dimen/activity_horizontal_margin"
  android:paddingtop="@dimen/activity_vertical_margin"
  xmlns:custom="http://schemas.android.com/apk/res-auto"
  android:background="#ffffff"
  >

  <!--自定义控件,继承relativelayout-->
  <qdong.com.mylibrary.circularloadingview
    android:id="@+id/simple"
    custom:base_color="@color/pager_bg"
    custom:min="0"
    custom:max="100"
    custom:argquantity="100"
    custom:ratio="0.6"
    custom:progress_color="@android:color/holo_green_light"
    custom:progress_icon="@mipmap/ic_launcher"
    custom:duration="1000"
    custom:progress_stroke_width="28"
    android:layout_centerinparent="true"
    android:layout_width="200dp"
    android:layout_height="200dp">

    <relativelayout
      android:layout_centerinparent="true"
      android:layout_width="match_parent"
      android:layout_height="match_parent">
      

        <textview
          android:layout_centerinparent="true"

          android:textsize="20sp"
          android:layout_centerhorizontal="true"
          android:id="@+id/number"
          android:text="0"
          android:gravity="center"
          android:textcolor="@color/pager_bg"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content" />

    </relativelayout>

  </qdong.com.mylibrary.circularloadingview>

  <button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="set_value"
    android:id="@+id/button"
    android:layout_alignparentbottom="true"
    android:layout_alignparentstart="true"/>

  <button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="animation"
    android:id="@+id/button3"
    android:layout_aligntop="@+id/button"
    android:layout_alignparentend="true"/>
</relativelayout>

mainactivity:

findviewbyid(r.id.button).setonclicklistener(new view.onclicklistener() {
  @override
  public void onclick(view view) {
    try {
      mdashedcircularprogress.setvalue(66);//没有动画的,直接设置
    } catch (exception e) {
      e.printstacktrace();
    }
  }
});
findviewbyid(r.id.button3).setonclicklistener(new view.onclicklistener() {
  @override
  public void onclick(view view) {
    try {
      mdashedcircularprogress.setvalue(0);//无动画,归零
      mdashedcircularprogress.setvaluewithanimation(100,2000);//带动画
    } catch (exception e) {
      e.printstacktrace();
    }
  }
});


github地址:https://github.com/506954774/androidcircularloadingview

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