Android 自定義view --圓形百分比(進度條)

jopen 8年前發布 | 146K 次閱讀 Android開發 移動開發

起因

    最近公司項目有需求需要用到輕量級圖表如下圖,是一些簡單的扇形圖,圓形圖,折線圖,雖然有好用的三方庫MPChart
    (教程地址http://blog.csdn.net/wingichoy/article/details/50428246),
    但是過于龐大,像這樣的簡約的界面明顯不合適,又因為許久沒有堅持寫博客,覺得自己很是墮落,深知自學不易,于是便想寫一些博客來幫助后來像我一樣的初學者,所以便想把這些效果寫一個系列。其中包括:
    1.圓形百分比圖表  
    2.簡易折線圖圖表
    3.簡易柱狀圖圖表

這里寫圖片描述

效果圖

說了這么多沒有效果圖還是廢話,效果圖如下:
這里寫圖片描述

預備知識

本篇博客的預備知識內容有:
1.自定義屬性
2.自定義view
關于以上兩點,可以查看 Hongyang大神的博客:自定義View(一)

知識點補充

如果你已經掌握了以上的基本知識,那么可以開始本篇博客的內容啦。但是還是有幾點內容補充。

1.MeasureSpec對象包含了測量的模式和大小。他是一個32位的int值,其中高兩位為測量的模式,低30位是測量的大小。采用位運算和運行效率有關。所以可以從一個MeasureSpec對象分別獲取模式和值 如:

//獲取模式  值為 EXACTLY AT_MOST UNSPECIFIED
int specMode = MeasureSpec.getMode(measureSpec);
//獲取測量值
int specSize = MeasureSpec.getSize(measureSpec);

2.畫扇形,調用drawArc()方法,其中第一個參數是圓所在的矩形,第二個參數是開始的弧度,值得主意的是,最頂的弧度是270度,而地圖東方向的弧度為0.第三個參數是需要畫的弧度,第四個參數是一個布爾值,表示是否連接圓心,畫為扇形,第五個是Paint,即所需要的畫筆。

canvas.drawArc(rect, 270, mEndAngle, true, sectorPaint);

現在開始吧

1.首先分析需求,我們的圓形進度總共分為三層,
最底層是一個大園形,作為底色。
第二層是一個扇形,大小跟底色一樣,用來表示進度。
第三層是一個小圓形,比背景色小,用于實現弧線的效果。

2.新建一個類叫做CirclePercentView.java 他繼承與View類重寫他的構造函數,來獲取他的自定義屬性。
    public CirclePercentView(Context context) {
        this(context, null);
    }

    public CirclePercentView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CirclePercentView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 獲取自定義屬性
        TypedArray a=context.obtainStyledAttributes(attrs,R.styleable.CirclePercentView, defStyleAttr, 0);

//獲取色帶的寬度
        mStripeWidth = a.getDimension(R.styleable.CirclePercentView_stripeWidth, PxUtils.dpToPx(30, context));
        //獲取當前的百分比
        mCurPercent = a.getInteger(R.styleable.CirclePercentView_percent, 0);
        //獲取小園的顏色
        mSmallColor = a.getColor(R.styleable.CirclePercentView_smallColor,0xffafb4db);
        //獲取大圓的顏色
        mBigColor = a.getColor(R.styleable.CirclePercentView_bigColor,0xff6950a1);
        //獲取中心文字的大小
        mCenterTextSize = a.getDimensionPixelSize(R.styleable.CirclePercentView_centerTextSize,PxUtils.spToPx(20,context));
        //獲取園的半徑
        mRadius = a.getDimensionPixelSize(R.styleable.CirclePercentView_radius,PxUtils.dpToPx(100,context));
    }   
3.獲取到了自定義屬性以后,我們來測量這個view,告訴系統這個view有多大
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //獲取測量模式
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        //獲取測量大小
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        //如果為確定大小值,則圓的半徑為寬度/2
        if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
            mRadius = widthSize / 2;
            x = widthSize / 2;
            y = heightSize / 2;
            mWidth = widthSize;
            mHeight = heightSize;
        }
        //如果為wrap_content 那么View大小為圓的半徑大小*2
        if(widthMode == MeasureSpec.AT_MOST&&heightMode ==MeasureSpec.AT_MOST){
            mWidth = (int) (mRadius*2);
            mHeight = (int) (mRadius*2);
            x = mRadius;
            y = mRadius;

        }
        //設置視圖的大小
        setMeasuredDimension(mWidth,mHeight);
    }
4.測量完成后,我們就要開始畫view了。首先畫大圓,之后畫扇形圖,最后畫小圓蓋住
就有了圓形進度條的效果,之后把百分比進度文字畫在上面就大功告成啦。

具體步驟如圖:這里寫圖片描述這里寫圖片描述這里寫圖片描述

    @Override
    protected void onDraw(Canvas canvas) {


        mEndAngle = (int) (mCurPercent * 3.6);
        //繪制大圓
        Paint bigCirclePaint = new Paint();
        //消除鋸齒
        bigCirclePaint.setAntiAlias(true);
        bigCirclePaint.setColor(mBigColor);
        //x,y 為圓心坐標 mRadius為半徑
        canvas.drawCircle(x, y, mRadius, bigCirclePaint);

         //餅狀圖
        Paint sectorPaint = new Paint();
        sectorPaint.setColor(mSmallColor);
        sectorPaint.setAntiAlias(true);
        RectF rect = new RectF(0, 0, mWidth, mHeight);
        //參數說明見知識補充
        canvas.drawArc(rect, 270, mEndAngle, true, sectorPaint);


        //繪制小圓
        Paint smallCirclePaint = new Paint();
        smallCirclePaint.setAntiAlias(true);
        smallCirclePaint.setColor(mBigColor);
        //圓心是相同的 不過半徑有差別,這個差別就是我們的 色帶寬度
        canvas.drawCircle(x, y, mRadius - mStripeWidth, smallCirclePaint);


        //繪制文本
        Paint textPaint = new Paint();
        String text = mCurPercent + "%";

        textPaint.setTextSize(mCenterTextSize);
        //測量字符串長度
        float textLength = textPaint.measureText(text);

        textPaint.setColor(Color.WHITE);
        //把文本畫在圓心居中
        canvas.drawText(text, x - textLength/2, y, textPaint);
}
值得注意的是,在編寫的過程中,文字的位置總是不對,但是根據畫圖計算,
公式是沒錯的,最后才發現我先測量了字符串長度,又修改了字體的大小導致偏差。所以一定要注意這些細節,先改變字體大小,再去測量。
5.添加setPercent方法
public void setPercent(int percent) {
//百分比不可能超過100 如果超過100則拋出異常 
        if (percent > 100) {
            throw new IllegalArgumentException("percent must less than 100!");
        }

        setCurPercent(percent);


    }
 //內部設置百分比 用于動畫效果
    private void setCurPercent(int percent) {

        mPercent = percent;

        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i =0;i<mPercent;i++){
                    try {
                        Thread.sleep(15);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    mCurPercent = i;
                    CirclePercentView.this.postInvalidate();
                }
                }

        }).start();

    }
這里在setPercent改變的時候,開啟一個線程,來不斷重繪view,達到一個動畫效果。其實view的動畫效果就是不停地重繪
(即執行onDraw(),因為每次執行onDraw()里面的參數會變化,所以會看到不同的畫面)。這樣便完成了一個輕量級的圓形百分比進度條自定義View。

你可以在https://github.com/githubwing/CirclePercentView克隆到源碼。(求star)
你還可以看本系列第二篇博客:簡易折線圖,鏈接:http://blog.csdn.net/wingichoy/article/details/50434634

來自: http://blog.csdn.net/wingichoy/article/details/50334595

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!