Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 自定義View控件之特殊的餅形圖(環形圖)

自定義View控件之特殊的餅形圖(環形圖)

編輯:關於Android編程

單位項目要實現如下圖這種環形圖或是說特殊的餅形圖,在網上找了半天,沒有發現開源的,沒法子,只能硬著頭皮自己寫一個了。最近也在學習自定義view。正好拿這個來進行練習一下。

\

先分析一下功能,
 1, 一共六個環形,每個顏色,弧度不同,
2, 在每個環形上,根據其環的弧度不同,在弧的中心點上,伸出線,在線上顯示相應的數值
 3, 在線的結尾處,顯示一個圓角方形,內部是其百分比。

一,六個環形的畫法
  
  一般在畫環形時,我們都是采用畫圈,然後設置其style為空心,給StrokeWidth一個值,用它來設置環的寬,可是這裡有一個問題,在設置完寬之後,它的這個寬是在邊為1的情況下,向內外擴展。說簡單一點,就是如果我們要畫一個半徑為100的環,如果你把StrokeWidth設成20,你會發現,最後畫出來的,是一個半徑為110的環。在這種情況下,我們在畫環上線的時候,算其長度會有麻煩。
  我采用了一個比較笨的方法,就是畫一個實心圓,然後再畫一個半徑減去環寬的小圓,這樣就達到了圓環的效果。這樣還有一個好處是,中心的圓的顏色也可以自定義了。
  這裡其實最麻煩的是算環形的半徑,這裡我一直也沒有想好有什麼太好的方法,我的方法比較笨,就是取控件的高度一半,然後再減去一個值,因為我認為,這個控件是一個寬大於高的控件,因為左右會有伸出的線嗎,所以相當來說,高就是比較小的哪個值,只所以還要減一個值,是因為要給線上的值,留一個空位出來,看一下效果圖,就明白什麼意思了。

二,環上的線

  這裡我采用了三角函數進行計算弧的中心點,然後根據它的不同位置進行畫線,這裡無非就是八種情況,向右上折,向右全直,向右下折,垂直向下然後右直,重直向下左直,向左上折,向左全直,向左下折。而直線的長度,我是根據線上的文字的長度來確定,然後左右各留出10的寬度.

三,在線尾處畫圓角方形和百分比

  前兩步做完,這一步就比較簡單了,采用drawRoundRect就可以很輕松的完成。

好了,分析到此為止,下面是代碼,裡面的注解比較清楚。

 

package com.example.cg.customcirclepre.custom;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import com.example.cg.customcirclepre.R;

import java.text.DecimalFormat;

/**
* 帶動畫的自定義餅形圖
* 作者:cg
* 時間:2016/9/6 0006 下午 2:48
*/
public class AnimationCirPre extends View {

    private float iBNum = 150;                                     //流入大單數
    private int iBColor = Color.parseColor("#EE755C");             //流入大單顏色
    private float iMNum = 200;                                     //流入中單數
    private int iMColor = Color.parseColor("#D7583E");             //流入中單顏色
    private float iSNum = 180;                                     //流入小單數
    private int iSColor = Color.parseColor("#C73F23");             //流入小單顏色
    private float oBNum = 660;                                     //流出大單數
    private int oBColor = Color.parseColor("#25D98E");             //流出大單顏色
    private float oMNum = 210;                                     //流出中單數
    private int oMColor = Color.parseColor("#2EBA80");             //流出中單顏色
    private float oSNum = 195;                                     //流出小單數
    private int oSColor = Color.parseColor("#1D8057");             //流出小單顏色

    private int StrokeWidth =  150;                                //弧的寬度
    private int TextSize = 50;                                     //文字大小

    private boolean isAnimation = false;                           //是否使用動畫效果
    private int AnimationSpeed = 2;                                //動畫的速度
    private int circleCenterColor = Color.parseColor("#ffffff");   //圓心顏色,默認是白色



    private Paint mPaint;                                          //畫筆
    private RectF mRectf;                                          //外圈圓的方形
    private Rect mBound;                                           //文字外框

    private String txtNumPre;                                      //顯示所占百分比
    float[] point;                                                 //記錄弧度最外邊中心點的坐標

    private int adjustDist = 20;                                   //在弧度上面的線,為了調整其最好的顯示位置設置一個調整的距離數

    private float txtBeginX = 0;                                   //線上文字開始的位置的X坐標值
    private float txtBeginY = 0;                                   //線上文字開始的位置的y坐標值
    private float txtEndX =0;                                      //線上文字結束的位置的x坐標值


    //計算總數
    private float sum;

    //計算六個值的百分比
    private float oBpre;
    private float oMpre;
    private float oSpre;
    private float iBpre;
    private float iMpre;
    private float iSpre;

    //計算六個值所占圓的弧度數
    private float oBArc;
    private float oMArc;
    private float oSArc;
    private float iBArc;
    private float iMArc;
    private float iSArc;

    //六個值弧度的初始值
    private float mOBArc = 1;
    private float mOMArc = 1;
    private float mOSArc = 1;
    private float mISArc = 1;
    private float mIMArc = 1;
    private float mIBArc = 1;


    public AnimationCirPre(Context context) {
        this(context,null);
    }

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

    public AnimationCirPre(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray array = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.MyPre, defStyleAttr, 0);
        int n = array.getIndexCount();
        for(int i=0;i= oBArc) {
                DrawOB(canvas, radius, oBArc, oBpre);
                mPaint.setColor(oMColor);
                canvas.drawArc(mRectf, 270 + oBArc, mOMArc, true, mPaint);
                mOMArc = mOMArc + AnimationSpeed;

                if (mOMArc <= oMArc) {
                    postInvalidate();
                }
            }

            //第三個
            if (mOMArc >= oMArc) {
                DrawOM(canvas, radius, oBArc, oMArc, oMpre);
                mPaint.setColor(oSColor);
                canvas.drawArc(mRectf, 270 + oBArc + oMArc, mOSArc, true, mPaint);
                mOSArc = mOSArc + AnimationSpeed;

                if (mOSArc <= oSArc) {
                    postInvalidate();
                }
            }

            //第四個
            if (mOSArc >= oSArc) {
                DrawOS(canvas, radius, oBArc + oMArc, oSArc, oSpre);
                mPaint.setColor(iSColor);
                canvas.drawArc(mRectf, 270 + oBArc + oMArc + oSArc, mISArc, true, mPaint);
                mISArc = mISArc + AnimationSpeed;

                if (mISArc <= iSArc) {
                    postInvalidate();
                }
            }

            //第五個
            if (mISArc >= iSArc) {
                DrawIS(canvas, radius, oBArc + oMArc + oSArc, iSArc, iSpre);
                mPaint.setColor(iMColor);
                canvas.drawArc(mRectf, 270 + oBArc + oMArc + oSArc + iSArc, mIMArc, true, mPaint);
                mIMArc = mIMArc + AnimationSpeed;

                if (mIMArc <= iMArc) {
                    postInvalidate();
                }
            }

            //第六個
            if (mIMArc >= iMArc ) {
                DrawIM(canvas, radius, oBArc + oMArc + oSArc + iSArc, iMArc, iMpre);
                mPaint.setColor(iBColor);
                canvas.drawArc(mRectf, 270 + oBArc + oMArc + oSArc + iSArc + iMArc, mIBArc, true, mPaint);
                mIBArc = mIBArc + AnimationSpeed;

                if (mIBArc <= iBArc + 1) {
                    postInvalidate();
                }
            }

            if (mIBArc >= iBArc) {
                DrawIB(canvas, radius, oBArc + oMArc + oSArc + iSArc + iMArc, iBArc, iBpre);
            }


        }else {

            /**
             * 畫出六個扇面
             */
            mPaint.setColor(oBColor);
            canvas.drawArc(mRectf, 270, oBArc, true, mPaint);

            mPaint.setColor(oMColor);
            canvas.drawArc(mRectf, 270 + oBArc, oMArc, true, mPaint);

            mPaint.setColor(oSColor);
            canvas.drawArc(mRectf, 270 + oBArc + oMArc, oSArc, true, mPaint);

            mPaint.setColor(iSColor);
            canvas.drawArc(mRectf, 270 + oBArc + oMArc + oSArc, iSArc, true, mPaint);

            mPaint.setColor(iMColor);
            canvas.drawArc(mRectf, 270 + oBArc + oMArc + oSArc + iSArc, iMArc, true, mPaint);

            mPaint.setColor(iBColor);
            canvas.drawArc(mRectf, 270 + oBArc + oMArc + oSArc + iSArc + iMArc, iBArc, true, mPaint);


            DrawOB(canvas, radius, oBArc, oBpre);

            DrawOM(canvas, radius, oBArc, oMArc, oMpre);

            DrawOS(canvas, radius, oBArc + oMArc, oSArc, oSpre);

            DrawIS(canvas, radius, oBArc + oMArc + oSArc, iSArc, iSpre);

            DrawIM(canvas, radius, oBArc + oMArc + oSArc + iSArc, iMArc, iMpre);

            DrawIB(canvas, radius, oBArc + oMArc + oSArc + iSArc + iMArc, iBArc, iBpre);
        }


        /**
         * 畫出中間的空白區域
         */
        mPaint.setColor(circleCenterColor);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius - StrokeWidth, mPaint);
    }


    /**
     * 流出大單
     * @param canvas     畫板
     * @param radius     中心半徑
     * @param oBArc      流出大單弧度
     * @param oBpre      流出大單百分比
     */
    public void DrawOB(Canvas canvas,float radius,float oBArc,float oBpre)
    {

        /**
         * 流出大單
         */
        if(oBNum>0)
        {
            //設置顯示的大單數量,在橫線上顯示的文字
            mPaint.setColor(oBColor);
            mPaint.setTextSize(TextSize);
            String txt = "大單  " + oBNum;
            mPaint.getTextBounds(txt, 0, txt.length(), mBound);


            //計算弧度的中心點
            point = new float[2];
            point[0] = (float)(radius * Math.cos(Math.PI * (Math.abs(90 - oBArc / 2)) / 180));
            point[1] = (float)(radius * Math.sin(Math.PI * (Math.abs(90 - oBArc / 2)) / 180));


            /**
             * 右側第一個弧度,無論為何值,它都不會在左半球,出現折線,所以它有四種情況
             * 1,弧度小於160時,它的中心線在90度以上,只所以沒有取180,是因為中間要留出20度,給直線,所以它有一個向上的折線。
             * 2,弧度小於等於200時,因為是一個else語句,所以它的中心點范圍是80--100,是一條直線。
             * 3,弧度小於340時,因為是一個else語句,所以它的中心點范圍是 100-170,是一條向下的折線。
             * 4,弧度小於360時,因為是一個else語句,所以它的中心點范圍是 170-180,它是一條向下垂直的線
             */
            //畫弧上的線
            drawLine(canvas, oBArc / 2, radius, 1);

            canvas.drawText(txt, txtEndX - mBound.width() - adjustDist / 2, txtBeginY - adjustDist / 2, mPaint);

            //畫線後的橢圓
            txtNumPre = getProValText(oBpre);
            mPaint.getTextBounds(txtNumPre, 0, txtNumPre.length(), mBound);
            mPaint.setStyle(Paint.Style.FILL);
            canvas.drawRoundRect(txtEndX + 10,
                    txtBeginY - mBound.height() / 2 - adjustDist/2,
                    txtEndX + adjustDist/2 + mBound.width() + 30,
                    txtBeginY - mBound.height() / 2 + mBound.height() + adjustDist/2,
                    15, 15, mPaint);
            mPaint.setColor(Color.parseColor("#ffffff"));
            canvas.drawText(txtNumPre, txtEndX + adjustDist / 2 + adjustDist / 2, txtBeginY + mBound.height() / 2, mPaint);
        }
    }

    /**
     * 流出中單
     * @param canvas     畫板
     * @param radius     中心半徑
     * @param oBArc      流出大單弧度
     * @param oMArc         流出中單弧度
     * @param oMpre      流出中單百分比
     */
    public void DrawOM(Canvas canvas,float radius,float oBArc,float oMArc,float oMpre)
    {
        if(oMNum>0)
        {
            mPaint.setColor(oMColor);
            mPaint.setTextSize(TextSize);
            String txt = "中單  " + oMNum;
            mPaint.getTextBounds(txt, 0, txt.length(), mBound);


            point = new float[2];
            point[0] = (float)(radius * Math.cos(Math.PI * (Math.abs(90 - (oMArc / 2 + oBArc))) / 180));
            point[1] = (float)(radius * Math.sin(Math.PI * (Math.abs(90 - (oMArc/2 + oBArc)))/180));


            /**
             * 右側第二個弧度,所以它有七種情況,它的情況與第一個弧度有關,所以它的弧度值要與第一個弧度進行相加來處理
             *   第一個弧度加上本身弧度的一半,可以得到中心點的位置,根據中心的位置進行判斷其位置
             * 1,弧度中心點小於80時,它的中心線在90度以上,只所以沒有取180,是因為中間要留出20度,給直線,所以它有一個向上的折線。
             * 2,弧度中心點小於等於100時,因為是一個else語句,所以它的中心點范圍是80--100,是一條直線。
             * 3,弧度中心點小於170時,因為是一個else語句,所以它的中心點范圍是 100-170,是一條向下的折線。
             * 4,弧度中心點小於180時,因為是一個else語句,所以它的中心點范圍是 170-180,它是一條向下垂直的線
             * 5,弧度中心點小於260時,因為是一個else語句,所以它會在左邊生成一個向下拆的線
             * 6,弧度中心點小於280時,因為是一個else語句,它會在左邊中間的位置生下一條直線
             * 7,弧度中心點於小360時,因為是一個else語句,它會在左邊上部,生成一個向上有折線的線
             */

            float oMCenterArc = oBArc + oMArc/2;


            //畫弧上的線
            drawLine(canvas, oMCenterArc, radius, 1);

            //畫出線上數據與後面橢圓型的百分比
            drawRect(canvas, txt, oMpre, oMCenterArc,1);
        }
    }

    /**
     * 流出小單
     * @param canvas     畫板
     * @param radius     中心半徑
     * @param oBMArc     流出大單和中單弧度和
     * @param oSArc      流出小單弧度
     * @param oSpre         流出小單百分比
     */
    public void DrawOS(Canvas canvas,float radius,float oBMArc,float oSArc,float oSpre)
    {
        if(oSNum>0)
        {
            mPaint.setColor(oSColor);
            mPaint.setTextSize(TextSize);
            String txt = "小單  " + oSNum;
            mPaint.getTextBounds(txt, 0, txt.length(), mBound);


            point = new float[2];
            point[0] = (float)(radius * Math.cos(Math.PI * (Math.abs(90 - (oSArc / 2 + oBMArc))) / 180));
            point[1] = (float)(radius * Math.sin(Math.PI * (Math.abs(90 - (oSArc/2 + oBMArc)))/180));


            float oMCenterArc = oBMArc + oSArc/2;

            //畫弧上的線
            drawLine(canvas,oMCenterArc,radius,1);

            drawRect(canvas,txt,oSpre,oMCenterArc,1);
        }
    }

    /**
     * 流入小單
     * @param canvas     畫板
     * @param radius     中心半徑
     * @param oBMSArc       流出大單,中單,小單弧度和
     * @param iSArc         流入小單弧度
     * @param iSpre         流入小單百分比
     */
    public void DrawIS(Canvas canvas,float radius,float oBMSArc,float iSArc,float iSpre)
    {
        if(iSNum>0)
        {
            mPaint.setColor(iSColor);
            mPaint.setTextSize(TextSize);
            String txt = "小單  " + iSNum;
            mPaint.getTextBounds(txt, 0, txt.length(), mBound);


            point = new float[2];
            point[0] = (float)(radius * Math.cos(Math.PI * (Math.abs(90 - (iSArc / 2 + oBMSArc))) / 180));
            point[1] = (float)(radius * Math.sin(Math.PI * (Math.abs(90 - (iSArc / 2 + oBMSArc))) / 180));


            float oMCenterArc = oBMSArc + iSArc/2;

            //畫弧上的線
            drawLine(canvas,oMCenterArc,radius,2);

            //畫出線上數據與後面橢圓型的百分比
            drawRect(canvas,txt,iSpre,oMCenterArc,2);
        }
    }

    /**
     * 流入中單
     * @param canvas     畫板
     * @param radius     中心半徑  
     * @param oBMSiMArc     流出大單,中單,小單,流入小單弧度和
     * @param iMArc         流入中單弧度
     * @param iMpre         流入中單百分比
     */
    public void DrawIM(Canvas canvas,float radius,float oBMSiMArc,float iMArc,float iMpre)
    {
        if(iMNum>0)
        {
            mPaint.setColor(iSColor);
            mPaint.setTextSize(TextSize);
            String txt = "中單  " + iMNum;
            mPaint.getTextBounds(txt, 0, txt.length(), mBound);


            point = new float[2];
            point[0] = (float)(radius * Math.cos(Math.PI * (Math.abs(90 - (iMArc / 2 + oBMSiMArc))) / 180));
            point[1] = (float)(radius * Math.sin(Math.PI * (Math.abs(90 - (iMArc/2 + oBMSiMArc)))/180));


            float oMCenterArc = oBMSiMArc + iMArc/2;

            //畫弧上的線
            drawLine(canvas, oMCenterArc, radius,2);

            //畫出線上數據與後面橢圓型的百分比
            drawRect(canvas,txt,iMpre,oMCenterArc,2);
        }
    }

    /**
     * 流入大單
     * @param canvas     畫板
     * @param radius        中心半徑
     * @param oBMSiSMArc    流出大單,中單,小單,流入小單,中單弧度和
     * @param iBArc         流入大單弧度
     * @param iBpre         流入大單百分比
     */
    public void DrawIB(Canvas canvas,float radius,float oBMSiSMArc,float iBArc,float iBpre)
    {
        if(iMNum>0)
        {
            mPaint.setColor(iSColor);
            mPaint.setTextSize(TextSize);
            String txt = "大單  " + iBNum;
            mPaint.getTextBounds(txt, 0, txt.length(), mBound);


            point = new float[2];
            point[0] = (float)(radius * Math.cos(Math.PI * (Math.abs(90 - (iBArc / 2 + oBMSiSMArc))) / 180));
            point[1] = (float)(radius * Math.sin(Math.PI * (Math.abs(90 - (iBArc/2 + oBMSiSMArc)))/180));

            float oMCenterArc = oBMSiSMArc + iBArc/2;

            //畫弧上的線
            drawLine(canvas,oMCenterArc,radius,2);

            //畫出線上數據與後面橢圓型的百分比
            drawRect(canvas,txt,iBpre,oMCenterArc,2);

        }
    }

    /**
     * 根據弧度值,來畫出弧度中心點伸出的線
     * @param canvas    畫板
     * @param sumArc    弧度之和
     * @param radius    中心半徑
     * @param flag      標識位,1:左側流出單 2:右側注入單
     */
    public void drawLine(Canvas canvas,float sumArc,float radius,int flag)
    {
        if(sumArc <= 80)
        {
            draw80(canvas);

        }else if(sumArc <=100) {
            draw100(canvas,sumArc);
        }else if(sumArc <=170){

            draw170(canvas);

        }else if(sumArc <=190)
        {
            draw180(canvas,radius,flag);

        }else if(sumArc <=260) {
            draw260(canvas);
        }
        else if(sumArc <=290) {
            draw280(canvas);
        }else
        {
            draw360(canvas);
        }
    }



    /**
     * 畫出弧度中心點小於80弧度的上面的線與值
     * 這裡的弧度中心點小於80,是它前面的所有弧度加上它本身的總度數的一半,如果是第一個弧,則為其本身的一半,此處畫出的是左側80度以下,帶有向上折線的兩根線
     * @param canvas   畫板
     */
    public void draw80(Canvas canvas)
    {
        txtBeginX = getWidth()/2 + point[0] + 40;
        txtBeginY = getHeight()/2 - point[1] - 20;

        canvas.drawLine(getWidth()/2 + point[0],
                getHeight()/2 - point[1],
                txtBeginX,
                txtBeginY,mPaint);

        txtEndX = txtBeginX + mBound.width() + 20;

        canvas.drawLine(txtBeginX,txtBeginY,
                txtEndX,txtBeginY,mPaint);
    }

    /**
     * 畫出弧度中心點大於等於80小於等於100弧度上面的線與值
     * 這裡的弧度中心點大於等於80小於等於100,是它前面的所有弧度加上它本身的總度數的一半,如果是第一個弧,則為其本身的一半,此處畫出的是左側80-100度之間,一根直線
     * @param canvas    畫板
     * @param sumArc    當前總弧度,當弧度大於90度時,其Y軸起始點應該向下移
     */
    public void draw100(Canvas canvas,float sumArc)
    {
        txtBeginX = getWidth() / 2 + point[0];
        if(sumArc>90)
        {
            txtBeginY = getHeight() / 2 + point[1];
        }else {
            txtBeginY = getHeight() / 2 - point[1];
        }

        txtEndX = txtBeginX + mBound.width() + adjustDist;

        canvas.drawLine(txtBeginX, txtBeginY,
                txtEndX, txtBeginY, mPaint);
    }

    /**
     * 畫出弧度中心點大於100小於170弧度上面的線與值
     * 這裡的弧度中心點大於100小於170,是它前面的所有弧度加上它本身的總度數的一半,如果是第一個弧,則為其本身的一半,此處畫出的是左側100-170度之間,帶有向下折線的兩根線
     * @param canvas   畫板
     */
    public void draw170(Canvas canvas)
    {
        txtBeginX = getWidth()/2 + point[0] + adjustDist*2;
        txtBeginY = getHeight()/2 + point[1] + adjustDist;

        canvas.drawLine(getWidth()/2 + point[0],
                getHeight()/2 + point[1],
                txtBeginX,
                txtBeginY, mPaint);

        txtEndX = txtBeginX + mBound.width() + adjustDist;

        canvas.drawLine(txtBeginX, txtBeginY,
                txtEndX, txtBeginY, mPaint);
    }


    /**
     * 畫出弧度中心點大於170小於190弧度上面的線與值
     * 這裡的弧度中心點大於170小於190,是它前面的所有弧度加上它本身的總度數的一半,如果是第一個弧,則為其本身的一半,此處畫出的是左側170-190度之間,帶有垂直向下折線的兩根線
     * @param canvas   畫板
     * @param radius   半徑
     * @param flag       標識位 1:右側流出量   2:左側流入量
     */
    public void draw180(Canvas canvas,float radius,int flag)
    {
        txtBeginX = getWidth() / 2 + point[0];
        txtBeginY = getHeight() / 2 + point[1] + adjustDist;

        canvas.drawLine(getWidth() / 2 + point[0],
                getHeight() / 2 + point[1],
                txtBeginX,
                txtBeginY, mPaint);

        //此處加一個判斷,主要是當在最下面畫線的時候,流出向右畫線,流入向左畫線
        if(flag==1) {
            txtEndX = txtBeginX + radius / 2 + mBound.width() + adjustDist;
        }else{
            txtEndX = txtBeginX - radius / 2 - mBound.width() - adjustDist;
        }

        canvas.drawLine(txtBeginX, txtBeginY,
                txtEndX, txtBeginY, mPaint);
    }

    /**
     * 畫出弧度中心點大於190,小於260弧度上面的線與值
     * 這裡的弧度中心點大於190小於260,是它前面的所有弧度加上它本身的總度數的一半,此處畫出的是左側190-260度之間,右邊帶有垂直向下折線的兩根線
     * @param canvas   畫板
     */
    public void draw260(Canvas canvas)
    {
        txtBeginX = getWidth() / 2 + point[0] - 40;
        txtBeginY = getHeight() / 2 + point[1] + 20;

        canvas.drawLine(getWidth() / 2 + point[0],
                getHeight() / 2 + point[1],
                txtBeginX,
                txtBeginY, mPaint);

        txtEndX = txtBeginX - mBound.width() - 20;

        canvas.drawLine(txtBeginX, txtBeginY,
                txtEndX, txtBeginY, mPaint);
    }

    /**
     * 畫出弧度中心點大於260,小於280弧度上面的線與值
     * 這裡的弧度中心點大於260小於280,是它前面的所有弧度加上它本身的總度數的一半,此處畫出的是左側260-280度之間,右邊的一根直線
     * @param canvas   畫板
     */
    public void draw280(Canvas canvas)
    {
        txtBeginX = getWidth() / 2 + point[0];
        txtBeginY = getHeight() / 2 + point[1];

        txtEndX = txtBeginX - mBound.width() - 20;

        canvas.drawLine(txtBeginX, txtBeginY,
                txtEndX, txtBeginY, mPaint);
    }

    /**
     * 畫出弧度中心點大於280,小於360弧度上面的線與值
     * 這裡的弧度中心點大於280小於360,是它前面的所有弧度加上它本身的總度數的一半,此處畫出的是左側280-360度之間,右邊向上折的兩根直線
     * @param canvas     畫板
     */
    public void draw360(Canvas canvas)
    {
        txtBeginX = getWidth()/2 + point[0] - 40;
        txtBeginY = getHeight()/2 + point[1] - 20;

        canvas.drawLine(getWidth() / 2 + point[0],
                getHeight() / 2 + point[1],
                txtBeginX,
                txtBeginY, mPaint);

        txtEndX = txtBeginX - mBound.width() - 20;

        canvas.drawLine(txtBeginX, txtBeginY,
                txtEndX, txtBeginY, mPaint);
    }


    /**
     * 畫線上的文字與後面橢圓型的百分比
     * @param canvas         畫板
     * @param txt            線上文字
     * @param iBpre          百分比
     * @param oMCenterArc    弧度數
     * @param flag           標識位 1: 右邊流出量  2: 左邊流入量
     */
    public void drawRect(Canvas canvas,String txt,float iBpre,float oMCenterArc,int flag)
    {
        if(oMCenterArc >=80 && oMCenterArc <=100)
        {

            draw100Rect(canvas,txt,iBpre);
        }
        else if(oMCenterArc<=190) {

            draw190Rect(canvas,txt,iBpre,flag,oMCenterArc);
        }else
        {

            drawOtherRect(canvas,txt,iBpre);
        }
    }


    /**
     * 處了右側第一個弧度外。當前弧度的一半加上之前弧度的和,在80-100之間,畫出線上文字與之後的百分比
     * @param canvas    畫板
     * @param txt     線上文字
     * @param oMpre     百分比
     */
    public void draw100Rect(Canvas canvas,String txt,float oMpre)
    {
        canvas.drawText(txt, txtBeginX + 10, txtBeginY - 10, mPaint);

        //畫線後的橢圓
        txtNumPre = getProValText(oMpre);
        mPaint.getTextBounds(txtNumPre, 0, txtNumPre.length(), mBound);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawRoundRect(txtEndX + 10,
                txtBeginY - mBound.height() / 2 - 10,
                txtEndX + 10 + mBound.width() + 30,
                txtBeginY - mBound.height() / 2 + mBound.height() + 10,
                15, 15, mPaint);
        mPaint.setColor(Color.parseColor("#ffffff"));
        canvas.drawText(txtNumPre, txtEndX + 10 + 10, txtBeginY + mBound.height() / 2, mPaint);
    }

    /**
     * 處了右側第一個弧度外。當前弧度的一半加上之前弧度的和,在小於等於190,並且不包括80-100的數據,畫出線上文字與之後的百分比
     * @param canvas   畫板
     * @param txt       線上文字
     * @param oMpre     百分比
     * @param flag      標識位  1:右側流出  2:左側流入
     * @param oMArc   弧度之和
     */
    public void draw190Rect(Canvas canvas,String txt,float oMpre,int flag,float oMArc)
    {
        //左側的流入三個弧度,如果在正下方,則特殊處理
        if(flag==2 && (oMArc>=170 && oMArc <=190))
        {
            canvas.drawText(txt, txtEndX + 20, txtBeginY - 10, mPaint);
            //畫線後的橢圓
            txtNumPre = getProValText(oMpre);
            mPaint.getTextBounds(txtNumPre, 0, txtNumPre.length(), mBound);
            mPaint.setStyle(Paint.Style.FILL);
            canvas.drawRoundRect(txtEndX - 10 - 10 - mBound.width() - 10 ,
                    txtBeginY - mBound.height() / 2 - 10,
                    txtEndX - 10,
                    txtBeginY - mBound.height() / 2 + mBound.height() + 10,
                    15, 15, mPaint);
            mPaint.setColor(Color.parseColor("#ffffff"));
            canvas.drawText(txtNumPre, txtEndX - 10 - 10 - mBound.width(), txtBeginY + mBound.height() / 2, mPaint);
        }else {
            canvas.drawText(txt, txtEndX - mBound.width() - 20, txtBeginY - 10, mPaint);
            //畫線後的橢圓
            txtNumPre = getProValText(oMpre);
            mPaint.getTextBounds(txtNumPre, 0, txtNumPre.length(), mBound);
            mPaint.setStyle(Paint.Style.FILL);
            canvas.drawRoundRect(txtEndX + 10,
                    txtBeginY - mBound.height() / 2 - 10,
                    txtEndX + 20 + mBound.width() + 20,
                    txtBeginY - mBound.height() / 2 + mBound.height() + 10,
                    15, 15, mPaint);
            mPaint.setColor(Color.parseColor("#ffffff"));
            canvas.drawText(txtNumPre, txtEndX + 20, txtBeginY + mBound.height() / 2, mPaint);
        }
    }

    /**
     * 處了右側第一個弧度外。當前弧度的一半加上之前弧度的和,在大於190,畫出線上文字與之後的百分比
     * @param canvas    畫板
     * @param txt       線上文字
     * @param oMpre     百分比
     */
    public void drawOtherRect(Canvas canvas,String txt,float oMpre)
    {
        canvas.drawText(txt, txtEndX + 10, txtBeginY - 10, mPaint);
        //畫線後的橢圓
        txtNumPre = getProValText(oMpre);
        mPaint.getTextBounds(txtNumPre, 0, txtNumPre.length(), mBound);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawRoundRect(txtEndX - 10 - mBound.width() - 30,
                txtBeginY - mBound.height() / 2 - 10,
                txtEndX - 10,
                txtBeginY - mBound.height() / 2 + mBound.height() + 10,
                15, 15, mPaint);
        mPaint.setColor(Color.parseColor("#ffffff"));
        canvas.drawText(txtNumPre, txtEndX - 10 - mBound.width() - 30 + 10, txtBeginY + mBound.height() / 2, mPaint);
    }




    /**
     * 格式化顯示的百分比
     * @param proValue   傳入的數值一般是0.1234這種格式的
     * @return           返回一個小數點後一位的百分比字符串
     */
    private String getProValText(float proValue)
    {
        DecimalFormat format = new DecimalFormat("#0.0");
        return format.format(proValue * 100) + "%";
    }


    public void setNum(float oBNum,float oMNum, float oSNum,float iBNum,float iMNum,float iSNum)
    {
        this.oBNum = oBNum;
        this.oMNum = oMNum;
        this.oSNum = oSNum;
        this.iBNum = iBNum;
        this.iMNum = iMNum;
        this.iSNum = iSNum;

        //計算總數
        sum = oBNum + oMNum + oSNum + iBNum + iMNum + iSNum;

        //計算六個值的百分比
        oBpre = oBNum / sum;
        oMpre = oMNum / sum;
        oSpre = oSNum / sum;
        iBpre = iBNum / sum;
        iMpre = iMNum / sum;
        iSpre = iSNum / sum;

        //計算六個值所占圓的弧度數
        oBArc = oBpre * 360;
        oMArc = oMpre * 360;
        oSArc = oSpre * 360;
        iBArc = iBpre * 360;
        iMArc = iMpre * 360;
        iSArc = iSpre * 360;

        mOBArc = 1;
        mOMArc = 1;
        mOSArc = 1;
        mISArc = 1;
        mIMArc = 1;
        mIBArc = 1;

        postInvalidate();
    }
}

attrs.xml文件

 

 



    //自定義屬性名,定義公共屬性
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

    //自定義控件的主題樣式
    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    


這裡說明一下,這個控件完全是為了效果圖而做,沒有做任何擴展。如果環數大於6的無法實現,小於6的,不要的值,要給0。

newCustomCirPre.java 純靜態圖

AnimationCirPre.java 添加了動畫效果。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved