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

android实现圆形渐变进度条

程序员文章站 2023-09-07 22:16:29
最近项目中使用到了渐变效果的圆形进度条,网上找了很多渐变效果不够圆滑,两个渐变颜色之间有明显的过渡,或者有些代码画出来的效果过渡不美观,于是自己参照写了一个,喜欢的朋友可以参考或者直接使用。先上一张效...

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

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

android实现圆形渐变进度条

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

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>

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