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

Android实现渐变圆环、圆形进度条效果

程序员文章站 2022-06-19 19:48:24
最近做了一个功能,里面涉及到了渐变圆形的需求。就是一个颜色可以渐变的圆环,最后实现的效果如下图: 左图是带渐变效果,右图是不带渐变效果。原理还是绘图,canv...

最近做了一个功能,里面涉及到了渐变圆形的需求。就是一个颜色可以渐变的圆环,最后实现的效果如下图:

Android实现渐变圆环、圆形进度条效果

Android实现渐变圆环、圆形进度条效果

左图是带渐变效果,右图是不带渐变效果。原理还是绘图,canvas可以绘制的对象有:弧线(arcs)、填充颜色(argb和color)、 bitmap、圆(circle和oval)、点(point)、线(line)、矩形(rect)、图片(picture)、圆角矩形 (roundrect)、文本(text)、顶点(vertices)、路径(path)。通过组合这些对象我们可以画出一些简单有趣的界面出来,但是光有这些功能还是不够的,如果我要画一个仪表盘(数字围绕显示在一个圆圈中)呢? 幸好android还提供了一些对canvas位置转换的方法:rorate、scale、translate、skew(扭曲)等,而且它允许你通过获得它的转换矩阵对象(getmatrix方法,不知道什么是转换矩阵?)  直接操作它。这些操作就像是虽然你的笔还是原来的地方画,但是画纸旋转或者移动了,所以你画的东西的方位就产生变化。为了方便一些转换操作,canvas 还提供了保存和回滚属性的方法(save和restore),比如你可以先保存目前画纸的位置(save),然后旋转90度,向下移动100像素后画一些图形,画完后调用restore方法返回到刚才保存的位置。

话不多说,上代码

核心类:

自定义控件 circleprogressbar

package com.jky.mobile_xmxt.view;
 
import android.content.context;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.graphics.rectf;
import android.graphics.sweepgradient;
import android.util.attributeset;
import android.view.view;
import android.view.animation.animation;
import android.view.animation.transformation;
 
import com.jky.mobile_xmxt.r;
 
import java.text.decimalformat;
 
/**
 * 圆盘计步图表
 */
public class circleprogressbar extends view {
 
 private rectf mwheelrect = new rectf();
 private paint mdefaultwheelpaint;
 private paint mfinishwheelpaint;
 private paint mcenterwheelpaint;
 private paint mtitlepaint, msteppaint, mtargetpaint;
 private float mcirclestrokewidth;
 private float msweepangleper;
 private float mpercent;
 private int mstepnum, mcurrstepnum;
 private float pressextrastrokewidth;
 private baranimation manim;
 private int mmaxstepnum;// 默认最大步数
 private float mtitley, mstepy, mtargety;
 private decimalformat mdecimalformat = new decimalformat("#.0");// 格式为保留小数点后一位
 public static string goal_step;
 public static string percent;
 
 public circleprogressbar(context context) {
 super(context);
 init(null, 0);
 }
 
 public circleprogressbar(context context, attributeset attrs) {
 super(context, attrs);
 init(attrs, 0);
 }
 
 public circleprogressbar(context context, attributeset attrs, int defstyle) {
 super(context, attrs, defstyle);
 init(attrs, defstyle);
 }
 
 private void init(attributeset attrs, int defstyle) {
 
 mfinishwheelpaint = new paint();
 mfinishwheelpaint.setcolor(color.rgb(100, 113, 205));
 mfinishwheelpaint.setstyle(paint.style.stroke);// 空心
 mfinishwheelpaint.setstrokecap(paint.cap.round);// 圆角画笔
 mfinishwheelpaint.setantialias(true);// 去锯齿
 
 mcenterwheelpaint = new paint();
 mcenterwheelpaint.setcolor(color.rgb(243, 243, 243));
 mcenterwheelpaint.setstyle(paint.style.stroke);
 mcenterwheelpaint.setstrokecap(paint.cap.round);
 mcenterwheelpaint.setantialias(true);
 
 mdefaultwheelpaint = new paint();
 mdefaultwheelpaint.setcolor(color.rgb(127, 127, 127));
 mdefaultwheelpaint.setstyle(paint.style.stroke);
 mdefaultwheelpaint.setstrokecap(paint.cap.round);
 mdefaultwheelpaint.setantialias(true);
 
 mtitlepaint = new paint();
 mtitlepaint.setantialias(true);
 mtitlepaint.setcolor(color.white);
 
 msteppaint = new paint();
 msteppaint.setantialias(true);
 msteppaint.setcolor(color.white);
 
 mtargetpaint = new paint();
 mtargetpaint.setantialias(true);
 mtargetpaint.setcolor(color.white);
 manim = new baranimation();
 }
 
 @override
 protected void ondraw(canvas canvas) {
 canvas.drawarc(mwheelrect, 0, 359, false, mdefaultwheelpaint);
 canvas.drawarc(mwheelrect, 0, 359, false, mcenterwheelpaint);
 canvas.drawarc(mwheelrect, 90, msweepangleper, false, mfinishwheelpaint);
// canvas.drawtext("步数", mwheelrect.centerx() - (mtitlepaint.measuretext("步数") / 2), mtitley,
// mtitlepaint);
 canvas.drawtext(mcurrstepnum + "",
  mwheelrect.centerx() - (msteppaint.measuretext(string.valueof(mcurrstepnum)) / 2), mstepy,
  msteppaint);
 string description = "";
 float percent = getpercent();
 if(percent > 0.5){
  description ="严重污染";
 }else if(percent<0.5){
  description ="中等污染";
 }else{
  description ="普通污染";
 }
 
 canvas.drawtext(description , mwheelrect.centerx() -
  (mtargetpaint.measuretext(description) / 2), mtargety, mtargetpaint);
 sweepgradient sweepgradient = new sweepgradient(mwheelrect.centerx(), mwheelrect.centery(),
  new int[]{getresources().getcolor(r.color.color_environment_severe), getresources().getcolor(r.color.color_environment_serious),
   getresources().getcolor(r.color.color_environment_excellent),
   getresources().getcolor(r.color.color_environment_good), getresources().getcolor(r.color.color_environment_mild),
   getresources().getcolor(r.color.color_environment_moderate)}, null);
 mfinishwheelpaint.setshader(sweepgradient);
 }
 
 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
 int height = getdefaultsize(getsuggestedminimumheight(), heightmeasurespec);
 int width = getdefaultsize(getsuggestedminimumwidth(), widthmeasurespec);
 int min = math.min(width, height);// 获取view最短边的长度
 setmeasureddimension(min, min);// 强制改view为以最短边为长度的正方形
 mcirclestrokewidth = gettextscale(15, min);// 圆弧的宽度
 pressextrastrokewidth = gettextscale(10, min);// 圆弧离矩形的距离
 mwheelrect.set(mcirclestrokewidth + pressextrastrokewidth, mcirclestrokewidth + pressextrastrokewidth,
  min - mcirclestrokewidth - pressextrastrokewidth, min - mcirclestrokewidth - pressextrastrokewidth);// 设置矩形
 mtitlepaint.settextsize(gettextscale(60, min));
 msteppaint.settextsize(gettextscale(120, min));
 mtargetpaint.settextsize(gettextscale(40, min));
 mtitley = gettextscale(170, min);
 mstepy = gettextscale(300, min);
 mtargety = gettextscale(380, min);
 mfinishwheelpaint.setstrokewidth(mcirclestrokewidth);
 mcenterwheelpaint.setstrokewidth(mcirclestrokewidth);
 mdefaultwheelpaint.setstrokewidth(mcirclestrokewidth - gettextscale(2, min));
 mdefaultwheelpaint.setshadowlayer(gettextscale(10, min), 0, 0, color.rgb(127, 127, 127));// 设置阴影
 }
 
 /**
 * 进度条动画
 *
 * @author administrator
 */
 public class baranimation extends animation {
 
 /**
  * 每次系统调用这个方法时, 改变msweepangleper,mpercent,stepnumbernow的值,
  * 然后调用postinvalidate()不停的绘制view。
  */
 @override
 protected void applytransformation(float interpolatedtime, transformation t) {
// if (interpolatedtime < 1.0f) {
// mpercent = float.parsefloat(mdecimalformat.format(interpolatedtime * mstepnum * 100f / mmaxstepnum));// 将浮点值四舍五入保留一位小数
// msweepangleper = interpolatedtime * mstepnum * 360 / mmaxstepnum;
// mcurrstepnum = (int) (interpolatedtime * mstepnum);
// } else {
  mpercent = float.parsefloat(mdecimalformat.format(mstepnum * 100f / mmaxstepnum));// 将浮点值四舍五入保留一位小数
  if (mpercent > 100.0f) {
  mpercent = 100.0f;
  }
  percent = string.valueof(mpercent);
  msweepangleper = mstepnum * 360 / mmaxstepnum;
  mcurrstepnum = mstepnum;
// }
 
  requestlayout();
 }
 }
 
 public float getpercent() {
 return mpercent;
 }
 
 /**
 * 根据控件的大小改变绝对位置的比例
 *
 * @param n
 * @param m
 * @return
 */
 public float gettextscale(float n, float m) {
 return n / 500 * m;
 }
 
 /**
 * 更新步数和设置一圈动画时间
 *
 * @param stepcount
 * @param time
 */
 public void update(int stepcount, int time) {
 this.mstepnum = stepcount;
 manim.setduration(time);
 // setanimationtime(time);
 this.startanimation(manim);
 }
 
 /**
 * @param stepnum
 */
 public void setmaxstepnum(int stepnum) {
 mmaxstepnum = stepnum;
 goal_step = string.valueof(mmaxstepnum);
 }
 
 public void setcolor(int color) {
 mfinishwheelpaint.setcolor(color);
 msteppaint.setcolor(color);
 }
 
 /**
 * 设置动画时间
 *
 * @param time
 */
 public void setanimationtime(int time) {
 manim.setduration(time * mstepnum / mmaxstepnum);// 按照比例设置动画执行时间
 }
 
}

xml引用

<com.jky.mobile_xmxt.view.circleprogressbar
 android:id="@+id/color_progress_view"
 android:layout_width="match_parent"
 android:layout_height="0dp"
 android:layout_weight="6"
 />

activity调用方法

color_progress_view = (circleprogressbar)view.findviewbyid(r.id.color_progress_view);
color_progress_view.setmaxstepnum(500);
color_progress_view.update(470,1000);

由于和调用其他控件方法类似,姑且省去了很多其他业务逻辑代码,代码不是特别复杂,修改起来也很方便(修改颜色,总量及比例等),所以只粘贴核心相关的代码,希望可以帮助到大家。

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