1. 程式人生 > >android自定義圓形進度條,實現動態畫圓效果

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);
	}