android自定义圆形进度条,实现动态画圆效果

时间:2021-01-01 05:43:16

自定义圆形进度条效果图如下:应用场景如动态显示分数等。

android自定义圆形进度条,实现动态画圆效果

view的自定义属性如下attr.xml

<?xml version="1.0" encoding="UTF-8"?>
<resources>
  
    <declare-styleable name="ArcProgressbar">
        <!-- 圆环起始角度-->
        <attr name="startAngle" format="integer" />
        <attr name="radius" format="integer" />
        <!-- 圆环的宽度  默认115-->
        <attr name="trokeWidth" format="integer" />
        <!-- 进度条进度颜色 -->
        <attr name="arcColor" format="color" />
    </declare-styleable>

</resources>

view代码如下:

package com.gdmob.ui;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;

import com.cwits.cex.picc.R;
/**
 * 自定义圆形进度条
 * @author hai
 *
 */
public class ArcProgressbar extends View {
	/**
	 * 圆环半径
	 */
	private int mRadius = 115; // Diameter英文为直径,该常量表示小圆直径的dp值
	/**
	 * 圆环的宽度
	 */
	private int mTrokeWidth = 15;
	/**
	 * 起始角度
	 */
	private int mStartAngle = 135;
	/**
	 * 进度条进度颜色
	 */
	private int mArcColor;

	private Paint mPaint;
	private int mProgress;// 表示进度
	private RectF mRect;
	private int mDiameter; // Diameter英文为直径,在该View中要绘制圆环,圆环由两个圆形确定(大圆和小圆),这个整形值表示小圆直径。
	private int mWidth;// 这个值表示圆环的宽度的2倍(大圆直径-小圆直径)

	private final int defaultColor; // 进度条背景颜色

	public ArcProgressbar(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		defaultColor = Color.TRANSPARENT;
		TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArcProgressbar, defStyle, 0);
		int num = ta.getIndexCount();
		for (int i = 0; i < num; i++) {
			int attr = ta.getIndex(i);
			switch (attr) {
			case R.styleable.ArcProgressbar_startAngle:
				mStartAngle = ta.getInt(attr, 135);
				break;
			case R.styleable.ArcProgressbar_arcColor:
				mArcColor = ta.getColor(attr, Color.parseColor("#eed306"));
				break;
			case R.styleable.ArcProgressbar_trokeWidth:
				mTrokeWidth = ta.getInt(attr, 15);
				break;
			case R.styleable.ArcProgressbar_radius:
				mRadius = ta.getInt(attr, 115);
				break;
			}
		}
		init();
	}

	public ArcProgressbar(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public ArcProgressbar(Context context) {
		this(context, null);
	}

	private void init() {
		Resources res = getResources();
		// getDisplayMetrics()返回当前展示的metrics.
		DisplayMetrics metrics = res.getDisplayMetrics();
		// TypedValue.applyDimension(int unit, float value, DisplayMetrics
		// metrics)
		// 该方法中unit表示要转换成的单位,value表示数值,metrics表示当前的度量方式
		// DIAMETER是常量0x1E,十进制为30,下面语句就表示tmp的值为30dp换算成的像素数值
		float tmp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mRadius, metrics);
		// ceil函数表示向上取整
		mDiameter = (int) Math.ceil(tmp);
		tmp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mTrokeWidth, metrics);
		mWidth = (int) Math.ceil(tmp);
		Paint p = new Paint();
		p.setStyle(Paint.Style.STROKE);
		p.setAntiAlias(true);
		// setStrokeWidth()设置画笔宽度
		// p.setStrokeWidth(0.5F*mWidth+0.5F*mDiameter);
		p.setStrokeWidth(0.4F * mWidth);
		p.setStrokeCap(Cap.ROUND);
		p.setColor(defaultColor);
		mPaint = p;

		float rightTop = (float) (mWidth / 2.0);// 这个值就是圆环宽度(大圆半径-小圆半径)
		mRect = new RectF(rightTop, rightTop, mDiameter + rightTop, mDiameter + rightTop);
		mProgress = 0;
	}

	protected boolean clear = false;

	@Override
	protected void onDraw(Canvas canvas) {
		// super.onDraw(canvas);

		// 如果mProgress<360,则圆形进度条还未旋转完成,则用0x7f的透明度绘制一个完整的圆形作为进度条背景
		// 注意要先绘制背景条,再绘制进度条,因为后绘制的会覆盖在先绘制的上面
		/*
		 * if (mProgress < 360) { paint.setAlpha(0x7f);
		 * paint.setColor(defaultColor); canvas.drawArc(mRect, 135, 270, false,
		 * paint); }
		 */
		if (clear) {
			mPaint.setColor(Color.TRANSPARENT);
			clear = false;
			return;
		}
		if (mProgress != 0) {
			Paint paint = mPaint;
			paint.setColor(mArcColor);
			float degree = (float) (360.0f * mProgress / 360);
			paint.setAlpha(0xff);
			paint.setColor(mArcColor);
			canvas.drawArc(mRect, mStartAngle, degree, false, paint);
		}
	}

	@Override
	protected final void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// mDiameter表示小圆直径,mWidth表示圆环宽度的2倍,所以meas表示大圆直径
		// 所以View的hight,width都为meas
		final int meas = mDiameter + mWidth;
		setMeasuredDimension(meas, meas);
	}

	public void setProgress(int p) {
		mProgress = p;
		invalidate();
	}

	public void postProgress(final int p) {
		post(new Runnable() {
			@Override
			public void run() {
				setProgress(p);
			}
		});
	}

	public void setmArcColor(int mArcColor) {
		this.mArcColor = mArcColor;
	}

	public void reset() {
		clear = true;
		invalidate();
		mProgress = 0;
	}
}

如上要让分数和进度条动态从0变到90,思路:定义一个变量mProgress=0,new一个定时任务,让mProgress慢慢从0 加到90后停止,

ArcProgressbar不停地调用setProgress(int p)就可以了。

代码如下:

	private void setGrade(final int g) {
		mProgress = 1;
		arcProgressbar.reset();
		final Handler handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				if (0 < (mProgress / 3.6) && (mProgress / 3.6) <= 59) {
					arcProgressbar.setmArcColor(Color.parseColor("#ff0000"));
					tv_grade.setTextColor(Color.parseColor("#ff0000"));
				} else if (60 < (mProgress / 3.6) && (mProgress / 3.6) <= 79) {
					arcProgressbar.setmArcColor(Color.parseColor("#f39700"));
					tv_grade.setTextColor(Color.parseColor("#f39700"));
				} else if (80 < (mProgress / 3.6) && (mProgress / 3.6) <= 100) {
					arcProgressbar.setmArcColor(Color.parseColor("#42ae7c"));
					tv_grade.setTextColor(Color.parseColor("#42ae7c"));
				}
				if (msg.what == 0x1223) {
					arcProgressbar.setProgress(mProgress * (1));
					tv_grade.setText("" + (int) (mProgress / 3.6));
				} else if (msg.what == 0x1224) {
					tv_grade.setText("" + g);
				}
			}
		};
		new Timer().schedule(new TimerTask() {
			@Override
			public void run() {
				Message msg = new Message();
				if (mProgress < (int) (((float) 360 / 100) * g)) {
					msg.what = 0x1223;
					mProgress++;
				} else {
					msg.what = 0x1224;
					this.cancel();
				}
				handler.sendMessage(msg);
			}
		}, 0, 5);
	}