天天看點

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

今天通過自定義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, );
    }

    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, );
        //下面是一些自定義參數的預設值
        mHasLoadColor = mContext.getResources().getColor(R.color.color_3398ab);
        mNormalLoadColor = mContext.getResources().getColor(R.color.color_e0e0e0);
        mRectangleWidth = dipToPixels(mContext, );
        mRectangleHeight = dipToPixels(mContext, );
        mRectangleNum = ;
        mInnerRadius = dipToPixels(mContext, );
        mTextSize = dipToPixels(mContext, );
        mRectangleRadius = dipToPixels(mContext, );
        mPercentStr = "0%";
        mPercent = f;
        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 / f, , mOuterRadius + mRectangleWidth / f, 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 + f);
        return valuePixels;
    }

    /**
     *供外界調用
     * 請在主線程調用,設定進度 0到1
     * @param percent
     */
    public void setPercent(@FloatRange(from=, to=) float percent){
        this.mPercent=percent;
        this.mPercentStr=Math.round(percent*)+"%";
        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //強制寬高度,在xml檔案中設定寬高無效
        //設定大小請根據半徑、小長方形大小來設定
        int defaultSize =  * (mInnerRadius + mRectangleHeight);
        setMeasuredDimension(defaultSize, defaultSize);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        int hasDownCount = ;//已經下載下傳百分比換算成需要畫多少個已經load的長方形
        hasDownCount = Math.round(mPercent * mRectangleNum);//才用四舍五入
        //旋轉之前先儲存下畫布的狀态
        canvas.save();
        //每次旋轉需要的角度
        float degress = f / mRectangleNum;
        for (int i = ; 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)) / ;
        //x預設是這個字元串的左邊在螢幕的位置,如果設定了paint.setTextAlign(Paint.Align.CENTER);那就是字元的中心,y是指定這個字元baseline在螢幕上的位置
        canvas.drawText(mPercentStr, mOuterRadius - textWidth / , mOuterRadius + diffBaseLine, mTextPaint);

    }
}
           
帶進度的圓形進度條的實作

代碼已上傳,連結位址LoadView