1. 程式人生 > >帶進度的圓形進度條的實現

帶進度的圓形進度條的實現

今天通過自定義View來實現一個帶進度的圓形進度條,實現的最終效果如下圖所示:
這裡寫圖片描述

現在來講一下設計的思路:首先這個進度條可以自定義小圓角矩形的數量、小圓角矩形大小、小圓角矩形的圓角角度、未完成進度時的顏色,完成進度時的顏色、文字大小、文字顏色、圓形半徑,所以需要自定義這些引數;那如何畫這個圓形進度呢?我們需要先畫一個小圓角矩形,再旋轉畫布再畫矩形,如圖這裡有12個小圓角矩形,每次旋轉360/12=30度,畫一個小圓角矩形,共畫12個。然後畫中間的進度值,畫中間的進度值,主要需要計算文字的位置,這個稍後再介紹。下面通過程式碼進行詳細的講解下實現過程。程式碼如下:

import android.content.Context;
import
android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Typeface; import android.support.annotation.FloatRange; import android.support.annotation.Nullable; import android.text.TextPaint; import android.util.AttributeSet; import
android.util.Log; import android.view.View; /** * Created by 劉信 on 2018/4/27. */ public class LoadView extends View { //已經load的顏色值 private int mHasLoadColor; //沒有load的顏色值 private int mNormalLoadColor; //小長方形的寬度 private int mRectangleWidth; //小長方形的高度 private int mRectangleHeight; //小長方形的個數
private int mRectangleNum; //小長方形圓角度 private int mRectangleRadius; //內半徑大小 //內半徑指不包括方塊的大小 private int mInnerRadius; //外半徑 private int mOuterRadius; //文字大小 private int mTextSize; //畫筆 private Paint mPaint; //文字的畫筆 private TextPaint mTextPaint; //小長方形 private RectF mRectF; private Context mContext; //百分比字串 private String mPercentStr; //百分比 private float mPercent; public LoadView(Context context) { this(context, null); } public LoadView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public LoadView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs, defStyleAttr); } private void init(Context context, AttributeSet attrs, int deStyleAttr) { mContext = context; TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.LoadView, deStyleAttr, 0); //下面是一些自定義引數的預設值 mHasLoadColor = mContext.getResources().getColor(R.color.color_3398ab); mNormalLoadColor = mContext.getResources().getColor(R.color.color_e0e0e0); mRectangleWidth = dipToPixels(mContext, 14); mRectangleHeight = dipToPixels(mContext, 28); mRectangleNum = 12; mInnerRadius = dipToPixels(mContext, 85); mTextSize = dipToPixels(mContext, 48); mRectangleRadius = dipToPixels(mContext, 3); mPercentStr = "0%"; mPercent = 0f; if (typedArray != null) { //從xml中讀取這些引數設定 mHasLoadColor = typedArray.getColor(R.styleable.LoadView_HasLoadColor, mHasLoadColor); mNormalLoadColor = typedArray.getColor(R.styleable.LoadView_NormalLoadColor, mNormalLoadColor); mRectangleWidth = typedArray.getDimensionPixelSize(R.styleable.LoadView_RectangleWidth, mRectangleWidth); mRectangleHeight = typedArray.getDimensionPixelSize(R.styleable.LoadView_RectangleHeight, mRectangleHeight); mRectangleNum = typedArray.getInteger(R.styleable.LoadView_RectangleNum, mRectangleNum); mInnerRadius = typedArray.getDimensionPixelSize(R.styleable.LoadView_InnerRadius, mInnerRadius); mTextSize = typedArray.getDimensionPixelSize(R.styleable.LoadView_TextSize, mTextSize); mRectangleRadius = typedArray.getDimensionPixelSize(R.styleable.LoadView_RectangleRadius, mRectangleRadius); typedArray.recycle(); } //外半徑等於使用者設定的內半徑加上小矩形的高度 mOuterRadius = mInnerRadius + mRectangleHeight; //這裡是畫第一個圓形矩形需要的RetcF。通過左上角和右下角座標確定, // 這裡左上角座標(mOuterRadius - mRectangleWidth / 2f,0), //右下角座標(mOuterRadius + mRectangleWidth / 2f, mRectangleHeight); mRectF = new RectF(mOuterRadius - mRectangleWidth / 2f, 0, mOuterRadius + mRectangleWidth / 2f, mRectangleHeight); mPaint = new Paint(); mPaint.setColor(mNormalLoadColor); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.FILL); mTextPaint = new TextPaint(); //這裡還可以設定文字的字型,我去掉了 /*try { Typeface typeface = Typeface.createFromFile("fonts/MyriadPro-Bold.otf"); mTextPaint.setTypeface(typeface); } catch (Exception e) { e.printStackTrace(); }*/ mTextPaint.setTextSize(mTextSize); mTextPaint.setColor(mHasLoadColor); } private int dipToPixels(Context context, float dip) { final float SCALE = context.getResources().getDisplayMetrics().density; float valueDips = dip; int valuePixels = (int)(valueDips * SCALE + 0.5f); return valuePixels; } /** *供外界呼叫 * 請在主執行緒呼叫,設定進度 0到1 * @param percent */ public void setPercent(@FloatRange(from=0.0, to=1.0) float percent){ this.mPercent=percent; this.mPercentStr=Math.round(percent*100)+"%"; invalidate(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //強制寬高度,在xml檔案中設定寬高無效 //設定大小請根據半徑、小長方形大小來設定 int defaultSize = 2 * (mInnerRadius + mRectangleHeight); setMeasuredDimension(defaultSize, defaultSize); } @Override protected void onDraw(Canvas canvas) { int hasDownCount = 0;//已經下載百分比換算成需要畫多少個已經load的長方形 hasDownCount = Math.round(mPercent * mRectangleNum);//才用四捨五入 //旋轉之前先儲存下畫布的狀態 canvas.save(); //每次旋轉需要的角度 float degress = 360.0f / mRectangleNum; for (int i = 0; i < mRectangleNum; i++) { if (hasDownCount > i) { //已經load的顏色 mPaint.setColor(mHasLoadColor); } else { //沒有load的顏色 mPaint.setColor(mNormalLoadColor); } //畫圓角矩形 canvas.drawRoundRect(mRectF, mRectangleRadius, mRectangleRadius, mPaint); //以中心點旋轉畫布,這裡想象下你現實中拿只筆在紙上畫,每畫一個你就旋轉紙,你就知道了 canvas.rotate(degress, mOuterRadius, mOuterRadius); } //回到之前的畫布狀態 canvas.restore(); //文字寬度 float textWidth = mTextPaint.measureText(mPercentStr); //計算高度要注意了 //drawText是以文字的BaseLine為準的 //所以計算高度步驟:文字高度(descent-ascent)的一半減去descent;得到的結果 // 是Baseline離中心圓點的偏移量,再加上半徑就是高度了 //還不懂?看下面的圖 Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics(); float diffBaseLine = (-(fontMetrics.ascent + fontMetrics.descent)) / 2; //x預設是這個字串的左邊在螢幕的位置,如果設定了paint.setTextAlign(Paint.Align.CENTER);那就是字元的中心,y是指定這個字元baseline在螢幕上的位置 canvas.drawText(mPercentStr, mOuterRadius - textWidth / 2, mOuterRadius + diffBaseLine, mTextPaint); } }