当前位置: 移动技术网 > 移动技术>移动开发>Android > android实现圆形渐变进度条

android实现圆形渐变进度条

2020年06月23日  | 移动技术网移动技术  | 我要评论

最近项目中使用到了渐变效果的圆形进度条,网上找了很多渐变效果不够圆滑,两个渐变颜色之间有明显的过渡,或者有些代码画出来的效果过渡不美观,于是自己参照写了一个,喜欢的朋友可以参考或者直接使用。

先上一张效果图,视频录制不太好,不过不影响效果

下面开始介绍实现代码,比较简单,直接贴代码吧

1、声明自定义属性

在项目的valuse文件夹下新建attrs.xml,在里面定义自定义控件需要的属性

<declare-styleable name="roundprogress">
    <attr name="bgcolor" format="color" />
    <attr name="roundwidth" format="dimension" />
    <attr name="textcolor" format="color" />
    <attr name="textsize" format="dimension" />
    <attr name="maxprogress" format="integer" />
    <attr name="textisdisplayable" format="boolean" />
    <attr name="linecolor" format="color" />
</declare-styleable>

2、自定义一个进度条roundprogres继承view类

package com.blankj.progressring;

import android.animation.valueanimator;
import android.content.context;
import android.content.res.typedarray;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.matrix;
import android.graphics.paint;
import android.graphics.rect;
import android.graphics.rectf;
import android.graphics.sweepgradient;
import android.graphics.typeface;
import android.util.attributeset;
import android.util.log;
import android.view.view;
import android.view.animation.linearinterpolator;

import org.jetbrains.annotations.nullable;

/**
 * 类描述:渐变的圆形进度条
 *
 * @author:lusy
 * @date :2018/10/17
 */
public class roundprogress extends view {
  private static final string tag = "roundprogress";
  /**
   * 背景圆环画笔
   */
  private paint bgpaint;
  /**
   * 白色标记画笔
   */
  private paint iconpaint;
  /**
   * 进度画笔
   */
  private paint progresspaint;
  /**
   * 进度文本画笔
   */
  private paint textpaint;
  /**
   * 背景圆环的颜色
   */
  private int bgcolor;
  /**
   * 线条进度的颜色
   */
  private int iconcolor;

  private int[] progresscolor;
  /**
   * 中间进度百分比的字符串的颜色
   */
  private int textcolor;
  /**
   * 中间进度百分比的字符串的字体大小
   */
  private float textsize;
  /**
   * 圆环的宽度
   */
  private float roundwidth;
  /**
   * 最大进度
   */
  private int max;
  /**
   * 当前进度
   */
  private float progress;
  /**
   * 是否显示中间的进度
   */
  private boolean textisdisplayable;
  /**
   * 圆环半径
   */
  private int mradius;
  private int center;

  private float startangle = -90;
  private float currentangle;
  private float currentprogress;

  public roundprogress(context context) {
    this(context, null);
  }

  public roundprogress(context context, @nullable attributeset attrs) {
    super(context, attrs);
    typedarray mtypedarray = context.obtainstyledattributes(attrs, r.styleable.roundprogress);

    //获取自定义属性和默认值
    bgcolor = mtypedarray.getcolor(r.styleable.roundprogress_bgcolor, color.parsecolor("#2d2d2d"));
    iconcolor = mtypedarray.getcolor(r.styleable.roundprogress_linecolor, color.parsecolor("#ffffff"));
    textcolor = mtypedarray.getcolor(r.styleable.roundprogress_textcolor, color.parsecolor("#ffffff"));
    textsize = mtypedarray.getdimension(r.styleable.roundprogress_textsize, 15);
    roundwidth = mtypedarray.getdimension(r.styleable.roundprogress_roundwidth, 5);
    max = mtypedarray.getinteger(r.styleable.roundprogress_maxprogress, 100);
    textisdisplayable = mtypedarray.getboolean(r.styleable.roundprogress_textisdisplayable, true);
    progresscolor = new int[]{color.parsecolor("#747eff"), color.parsecolor("#0018ff"), color.transparent};
    mtypedarray.recycle();
    initpaint();
  }

  public roundprogress(context context, @nullable attributeset attrs, int defstyleattr) {
    super(context, attrs, defstyleattr);
  }


  @override
  protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
    //测量控件应占的宽高大小,此处非必需,只是为了确保布局中设置的宽高不一致时仍显示完整的圆
    int measurewidth = measurespec.getsize(widthmeasurespec);
    int measureheight = measurespec.getsize(heightmeasurespec);
    setmeasureddimension(math.min(measurewidth, measureheight), math.min(measurewidth, measureheight));
  }

  private void initpaint() {

    bgpaint = new paint();
    bgpaint.setstyle(paint.style.stroke);
    bgpaint.setantialias(true);
    bgpaint.setcolor(bgcolor);
    bgpaint.setstrokewidth(roundwidth);

    iconpaint = new paint();
    iconpaint.setstyle(paint.style.stroke);
    iconpaint.setantialias(true);
    iconpaint.setcolor(iconcolor);
    iconpaint.setstrokewidth(roundwidth);

    progresspaint = new paint();
    progresspaint.setstyle(paint.style.stroke);
    progresspaint.setantialias(true);
    progresspaint.setstrokewidth(roundwidth);

    textpaint = new paint();
    textpaint.setstyle(paint.style.stroke);
    textpaint.settypeface(typeface.default_bold);
    textpaint.setantialias(true);
    textpaint.setcolor(textcolor);
    textpaint.settextsize(textsize);
    textpaint.setstrokewidth(0);


  }

  @override
  protected void ondraw(canvas canvas) {
    /**
     * 画最外层的大圆环
     */
    //获取圆心的x坐标
    center = math.min(getwidth(), getheight()) / 2;
    // 圆环的半径
    mradius = (int) (center - roundwidth / 2);

    rectf oval = new rectf(center - mradius, center - mradius, center + mradius, center + mradius);
    //画背景圆环
    canvas.drawarc(oval, startangle, 360, false, bgpaint);
    //画进度圆环
    drawprogress(canvas, oval);

    canvas.drawarc(oval, startangle, currentangle, false, progresspaint);
    //画白色圆环
    float start = startangle + currentangle - 1;
    canvas.drawarc(oval, start, 3, false, iconpaint);

    //百分比文字
    int percent = (int) (((float) progress / (float) max) * 100);
    //测量字体宽度,我们需要根据字体的宽度设置在圆环中间
    string text = string.valueof(percent)+"%";
    rect textrect = new rect();
    textpaint.gettextbounds(text, 0, text.length(), textrect);
    if (textisdisplayable && percent >= 0) {
      //画出进度百分比文字
      float x = (getwidth() - textrect.width()) / 2;
      float y = (getheight() + textrect.height()) / 2;
      canvas.drawtext(text, x, y, textpaint);
    }
    if (currentprogress < progress) {
      currentprogress++;
      postinvalidate();
    }

  }

  /**
   * 画进度圆环
   *
   * @param canvas
   * @param oval
   */
  private void drawprogress(canvas canvas, rectf oval) {
    float section = progress / 100;
    currentangle = section * 360;
    //把需要绘制的角度分成100等分
    float unitangle = (float) (currentangle / 100.0);
    for (float i = 0, end = currentprogress * unitangle; i <= end; i++) {
      sweepgradient shader = new sweepgradient(center, center, progresscolor, new float[]{0.0f, section, 1.0f});
      matrix matrix = new matrix();
      matrix.setrotate(startangle, center, center);
      shader.setlocalmatrix(matrix);
      progresspaint.setshader(shader);
      canvas.drawarc(oval,
          startangle + i,
          1,
          false,
          progresspaint);
    }
  }


  @override
  protected void onsizechanged(int w, int h, int oldw, int oldh) {
    super.onsizechanged(w, h, oldw, oldh);
    //计算外圆半径 宽,高最小值-填充边距/2
    center = (math.min(w, h)) / 2;
    mradius = (int) ((math.min(w, h)) - roundwidth / 2);

  }


  public int getmax() {
    return max;
  }

  /**
   * 设置进度的最大值
   *
   * @param max
   */
  public void setmax(int max) {
    if (max < 0) {
      log.e(tag, "max progress not allow <0");
      return;
    }
    this.max = max;
  }

  /**
   * 获取进度
   *
   * @return
   */
  public float getprogress() {
    return progress;
  }

  /**
   * 设置进度
   *
   * @param progressvalue
   * @param useanima   是否需要动画
   */

  public void setprogress(float progressvalue, boolean useanima) {
    float percent = progressvalue * max / 100;
    if (percent < 0) {
      percent = 0;
    }
    if (percent > 100) {
      percent = 100;
    }
    //使用动画
    if (useanima) {
      valueanimator valueanimator = valueanimator.offloat(0, percent);
      valueanimator.addupdatelistener(new valueanimator.animatorupdatelistener() {
        @override
        public void onanimationupdate(valueanimator animation) {
          progress = (float) animation.getanimatedvalue();
          postinvalidate();
        }
      });
      valueanimator.setinterpolator(new linearinterpolator());
      valueanimator.setduration(1500);
      valueanimator.start();
    } else {
      this.progress = percent;
      postinvalidate();
    }
  }


  public int gettextcolor() {
    return textcolor;
  }

  public void settextcolor(int textcolor) {
    this.textcolor = textcolor;
  }

  public float gettextsize() {
    return textsize;
  }

  public void settextsize(float textsize) {
    this.textsize = textsize;
  }

  public float getroundwidth() {
    return roundwidth;
  }

  public void setroundwidth(float roundwidth) {
    this.roundwidth = roundwidth;
  }

  public int[] getprogresscolor() {
    return progresscolor;
  }

  public void setprogresscolor(int[] progresscolor) {
    this.progresscolor = progresscolor;
    postinvalidate();
  }

  public int getbgcolor() {
    return bgcolor;
  }

  public void setbgcolor(int bgcolor) {
    this.bgcolor = bgcolor;
  }

  public int geticoncolor() {
    return iconcolor;
  }

  public void seticoncolor(int iconcolor) {
    this.iconcolor = iconcolor;
  }

  public boolean istextisdisplayable() {
    return textisdisplayable;
  }

  public void settextisdisplayable(boolean textisdisplayable) {
    this.textisdisplayable = textisdisplayable;
  }

  public int getmradius() {
    return mradius;
  }

  public void setmradius(int mradius) {
    this.mradius = mradius;
  }

  public int getcenter() {
    return center;
  }

  public void setcenter(int center) {
    this.center = center;
  }

  public float getstartangle() {
    return startangle;
  }

  public void setstartangle(float startangle) {
    this.startangle = startangle;
  }
}

3、使用自定义进度条view

activity布局文件使用如下,为了方便测试效果,新增进度加、进度减,修改进度条颜色的按钮

<?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="#242424"
  android:gravity="center">


  <linearlayout
    android:id="@+id/buttonlayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="20dp"
    android:gravity="center_horizontal"
    android:orientation="horizontal">

    <button
      android:id="@+id/addprogress"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="进度+" />

    <button
      android:id="@+id/changecolor"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginleft="10dp"
      android:layout_marginright="10dp"
      android:text="设置颜色" />

    <button
      android:id="@+id/subtraceprogress"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="进度-" />
  </linearlayout>

  <com.blankj.progressring.roundprogress
    android:id="@+id/socprogress"
    android:layout_width="70dp"
    android:layout_height="70dp"
    android:layout_below="@id/buttonlayout"
    android:layout_centerhorizontal="true"
    android:layout_gravity="center"
    android:layout_marginleft="20dp"
    android:layout_marginbottom="2dp"
    app:bgcolor="@color/bgcolor"
    app:maxprogress="100"
    app:roundwidth="8dp"
    app:textisdisplayable="true"
    app:textsize="18sp" />

</relativelayout>

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网