android自定義圓形進度條,實現動態畫圓效果
阿新 • • 發佈:2019-01-01
自定義圓形進度條效果圖如下:應用場景如動態顯示分數等。
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); }