1. 程式人生 > >自定義圓形進度條(一)

自定義圓形進度條(一)

由於專案需要,需要自定義一個圓形進度條,效果如下:

這裡寫圖片描述

1 建立什麼檔案?

這裡寫圖片描述

具體的程式碼我會放在github上,所以暫時忽略attr檔案和activity_main2檔案

2 CustomCircleProgressBar

package com.demo1.views;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import
android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.support.v4.content.ContextCompat; import android.util.AttributeSet; import android.view.View; import android.view.animation.LinearInterpolator; import com.demo1.R; import
static android.graphics.Paint.Style.STROKE; public class CustomCircleProgressBar extends View { private int outsideColor; //進度的顏色 private float circleRadius; //外圓半徑大小 private int insideColor; //背景顏色 private int progressTextColor; //圓環內文字顏色 private float progressTextSize; //圓環內文字大小
private float progressWidth; //圓環的寬度 private int maxProgress; //最大進度 private float progress; //當前進度 private Paint paint; private String progressText; //圓環內文字 private Rect rect; private ValueAnimator animator; public CustomCircleProgressBar(Context context) { this(context, null); } public CustomCircleProgressBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomCircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomCircleProgressBar, defStyleAttr, 0); outsideColor = a.getColor(R.styleable.CustomCircleProgressBar_outside_color, ContextCompat.getColor(getContext(), R.color.colorPrimary)); circleRadius = a.getDimension(R.styleable.CustomCircleProgressBar_circle_radius, dp2px(getContext(), 60.0f)); insideColor = a.getColor(R.styleable.CustomCircleProgressBar_inside_color, ContextCompat.getColor(getContext(), R.color.inside_color)); progressTextColor = a.getColor(R.styleable.CustomCircleProgressBar_progress_text_color, ContextCompat.getColor(getContext(), R.color.colorPrimary)); progressTextSize = a.getDimension(R.styleable.CustomCircleProgressBar_progress_text_size, dp2px(getContext(), 14.0f)); progressWidth = a.getDimension(R.styleable.CustomCircleProgressBar_progress_width, dp2px(getContext(), 10.0f)); progress = a.getFloat(R.styleable.CustomCircleProgressBar_progress, 50.0f); maxProgress = a.getInt(R.styleable.CustomCircleProgressBar_max_progress, 100); a.recycle(); paint = new Paint(); } /** * dp轉px */ public static int dp2px(Context context, float dp) { return (int) (dp * context.getResources().getDisplayMetrics().density + 0.5f); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int circlePoint = getMeasuredWidth() / 2; //第一步:畫背景(即內層圓) paint.setColor(insideColor); //設定圓的顏色 paint.setStyle(STROKE); //設定空心 paint.setStrokeWidth(progressWidth); //設定圓的寬度 paint.setAntiAlias(true); //消除鋸齒 canvas.drawCircle(circlePoint, circlePoint, circleRadius, paint); //畫出圓 //第二步:畫進度(圓弧) paint.setColor(outsideColor); //設定進度的顏色 RectF oval = new RectF(circlePoint - circleRadius, circlePoint - circleRadius, circlePoint + circleRadius, circlePoint + circleRadius); //用於定義的圓弧的形狀和大小的界限 canvas.drawArc(oval, -90, 360 * (progress / maxProgress), false, paint); //根據進度畫圓弧 //第三步:畫圓環內百分比文字 rect = new Rect(); paint.setColor(progressTextColor); paint.setTextSize(progressTextSize); paint.setStrokeWidth(0); progressText = getProgressText(); paint.getTextBounds(progressText, 0, progressText.length(), rect); Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt(); int baseline = (getMeasuredHeight() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top; //獲得文字的基準線 canvas.drawText(progressText, getMeasuredWidth() / 2 - rect.width() / 2, baseline, paint); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width; int height; int size = MeasureSpec.getSize(widthMeasureSpec); int mode = MeasureSpec.getMode(widthMeasureSpec); if (mode == MeasureSpec.EXACTLY) { width = size; } else { width = (int) ((2 * circleRadius) + progressWidth); } size = MeasureSpec.getSize(heightMeasureSpec); mode = MeasureSpec.getMode(heightMeasureSpec); if (mode == MeasureSpec.EXACTLY) { height = size; } else { height = (int) ((2 * circleRadius) + progressWidth); } setMeasuredDimension(width, height); } //中間的進度百分比 private String getProgressText() { return (int) ((progress / maxProgress) * 100) + "%"; } public synchronized int getMaxProgress() { return maxProgress; } public synchronized void setMaxProgress(int maxProgress) { if (maxProgress < 0) { //此為傳遞非法引數異常 throw new IllegalArgumentException("maxProgress should not be less than 0"); } this.maxProgress = maxProgress; } public synchronized float getProgress() { return progress; } //加鎖保證執行緒安全,能線上程中使用 public synchronized void setProgress(int progress) { if (progress < 0) { throw new IllegalArgumentException("progress should not be less than 0"); } if (progress > maxProgress) { progress = maxProgress; } startAnim(progress); } /** * 設定動畫 * @param progress 進度的整數 80,100,等值 */ private void startAnim(float progress) { animator = ObjectAnimator.ofFloat(0, progress); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { CustomCircleProgressBar.this.progress = (float) animation.getAnimatedValue(); postInvalidate(); } }); animator.setStartDelay(500); animator.setDuration(2000); animator.setInterpolator(new LinearInterpolator());//勻速動畫 animator.start(); } }

如果不研究原始碼也不想了解來龍去脈的話到這裡就可以結束了,這是原始碼地址

如果有時間研究原始碼歡迎瀏覽我的下一篇部落格:

自定義圓形進度條(二)