Android開發自定義控制元件實現一個餅狀圖

王世暉發表於2016-05-09

實現一個如圖所示的控制元件,包括兩部分,左邊的餅狀圖和中間的兩個小方塊,及右邊的兩行文字


實現起來比較簡單,只是一些繪圖API的呼叫

核心程式碼在onDraw函式裡邊,,對靜態控制元件進行繪製即可

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    /*餅狀圖的x座標*/
    float centreX=  getWidth()/5;
    /*餅狀圖的y座標*/
    float centreY= getHeight()/2;
    /*文字的大小*/
    float textSize=getHeight()/7;
    float width=(float)getWidth();
    float height=(float)getHeight();
    /*中間小正方形邊長的一半*/
    float halfSmallRec =((float)getHeight())*3/70;
    percent =((float) mBigBallNumber)/(mBigBallNumber + mSmallBallNumber);
    /*求餅狀圖的半徑*/
    radius= Math.min(getWidth() * 1 / 8, getHeight() * 10 / 35);
    /*構建一個正方形,餅狀圖是這個正方形的內切圓*/
    rectf=new RectF((int)(centreX-radius),(int)(centreY-radius),(int)(centreX+radius),(int)(centreY+radius));
    /*設定餅狀圖畫筆的顏色,先繪製大球佔的比例*/
    piePaint.setColor(mBigBallColor);
    /*The arc is drawn clockwise. An angle of 0 degrees correspond to the
    * geometric angle of 0 degrees (3 o'clock on a watch.)*/
    /*drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint)*/
    /*繪製大球的扇形圖,float startAngle起始角度的0度的位置在3點鐘方向
    * 因此大球的扇形圖要從12點鐘開始繪製,所以起始角度為270度*/
    canvas.drawArc(rectf, 270, 360 * percent, true, piePaint);
    /*換種顏色,開始繪製小球佔的餅狀圖*/
    piePaint.setColor(mSmallBallColor);
    /*起始角度就是12點鐘加上360度乘以大球佔的比例,12點鐘轉換為起始角度為270度*/
    canvas.drawArc(rectf, 270 + 360 * percent, 360 - 360 * percent, true, piePaint);
    /*顏色更改為大球的顏色*/
    piePaint.setColor(mBigBallColor);
    /*繪製上邊的小方塊,也就是大球的方塊*/
    canvas.drawRect(width * 2 / 5 - halfSmallRec, height* 23/ 60 - halfSmallRec, width * 2 / 5 + halfSmallRec, height *23/ 60 + halfSmallRec, piePaint);
    /*更改畫筆顏色為小球顏色*/
    piePaint.setColor(mSmallBallColor);
    /*繪製下邊的小方塊即小球的小方塊*/
    canvas.drawRect(width * 2 / 5 - halfSmallRec, height * 37 / 60 - halfSmallRec, width * 2 / 5 + halfSmallRec, height * 37 / 60 + halfSmallRec, piePaint);
    /*開始繪製文字,先設定文字顏色*/
    textPaint.setColor(getResources().getColor(typedValue.resourceId));
    /*設定問題大小*/
    textPaint.setTextSize(textSize);
    /*大球數量*/
    String strBig = strBigBallName + mBigBallNumber;
    /*測量文字寬度*/
    float textBigWidth =textPaint.measureText(strBig);
    Paint.FontMetrics fontMetrics=textPaint.getFontMetrics();
    /*繪製上邊大球數量*/
    canvas.drawText(strBig, width * 9 / 20 + textBigWidth / 2, height *23/ 60 - fontMetrics.top / 3, textPaint);
    /*小球數量*/
    String strSmall = strSmallBallName + mSmallBallNumber;
    /*測量文字寬度*/
    float textUnderWidth=textPaint.measureText(strSmall);
    /*繪製下邊的小球數量*/
    canvas.drawText(strSmall,width*9/20+textUnderWidth/2,height*37/60-fontMetrics.top/3,textPaint);
    /*更改畫筆顏色,開始繪製百分比*/
    textPaint.setColor(getResources().getColor(R.color.half_transparent));
    String strBigPercent =" ("+ mPercentBigBall +")";
    /*測量大球百分比文字寬度*/
    float bigPercent =textPaint.measureText(strBigPercent);
    /*drawText(String text, float x, float y, Paint paint)
    * 繪製文字的API,四個引數分別是文字內容,起始繪製x座標,起始繪製y座標,畫筆
    * 以為設定了居中繪製,因此穿進去的xy座標為文字的中心點*/
    canvas.drawText(strBigPercent, width * 9 / 20+ textBigWidth + bigPercent /2, height*23 / 60-fontMetrics.top*1/3, textPaint);
    /*同樣的道理繪製小球的百分比*/
    String strSmallPercent =" ("+ mPercentSmallBall +")";
    float smallPercent =textPaint.measureText(strSmallPercent);
    canvas.drawText(strSmallPercent,width*9/20+textUnderWidth+ smallPercent /2,height*37/60-fontMetrics.top/3,textPaint);
}
Canvas 繪製文字時,使用FontMetrics物件,計算位置的座標。參考:http://blog.csdn.net/tianjf0514/article/details/7642656


設定文字繪製以中心為起點開始繪製

textPaint.setTextAlign(Paint.Align.CENTER);

x的座標好計算,y座標需要按需使用FontMetrics幾個屬性即可

完整程式碼如下:

public class PieHalfView extends View {
    /*左邊餅狀圖的畫筆*/
    private Paint piePaint;
    /*右邊文字的畫筆*/
    private Paint textPaint;
    /*餅狀圖的半徑*/
    private float radius;
    private RectF rectf;
    /*餅狀圖中第一個扇形佔整個圓的比例*/
    private float percent;
    /*深淺兩種顏色*/
    private int mBigBallColor, mSmallBallColor;
    /*大小球的數量*/
    private int mBigBallNumber;
    private int mSmallBallNumber;
    /*大小球所佔的百分比*/
    private String mPercentBigBall;
    private String mPercentSmallBall;
    /*動態獲取屬性*/
    private TypedValue typedValue;
    /*中間的文字資訊*/
    private String strBigBallName;
    private String strSmallBallName;

    public PieHalfView(Context context) {
        super(context);
        init(context);
    }

    public PieHalfView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public PieHalfView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }
    private void init(Context context) {
        /*設定餅狀圖畫筆*/
        piePaint =new Paint();
        piePaint.setAntiAlias(true);
        piePaint.setStyle(Paint.Style.FILL);
        /*設定文字畫筆*/
        textPaint=new Paint();
        textPaint.setStyle(Paint.Style.STROKE);
        textPaint.setAntiAlias(true);
        textPaint.setTextAlign(Paint.Align.CENTER);
        /*下邊設定一些預設的值,如果呼叫者沒有傳值進來的話,用這些預設值*/
        mBigBallColor = 0xFF9CCA5D;
        mSmallBallColor =0xFF5F7048;
        /*TypedValue:Container for a dynamically typed data value. Primarily used with Resources for holding resource values.*/
        typedValue=new TypedValue();
        context.getTheme().resolveAttribute(R.attr.maintextclor,typedValue,true);
        mBigBallNumber =1;
        mSmallBallNumber =3;
        mPercentBigBall ="40%";
        mPercentSmallBall ="60%";
        strBigBallName =getResources().getString(R.string.big);
        strSmallBallName =getResources().getString(R.string.small);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /*餅狀圖的x座標*/
        float centreX=  getWidth()/5;
        /*餅狀圖的y座標*/
        float centreY= getHeight()/2;
        /*文字的大小*/
        float textSize=getHeight()/7;
        float width=(float)getWidth();
        float height=(float)getHeight();
        /*中間小正方形邊長的一半*/
        float halfSmallRec =((float)getHeight())*3/70;
        percent =((float) mBigBallNumber)/(mBigBallNumber + mSmallBallNumber);
        /*求餅狀圖的半徑*/
        radius= Math.min(getWidth() * 1 / 8, getHeight() * 10 / 35);
        /*構建一個正方形,餅狀圖是這個正方形的內切圓*/
        rectf=new RectF((int)(centreX-radius),(int)(centreY-radius),(int)(centreX+radius),(int)(centreY+radius));
        /*設定餅狀圖畫筆的顏色,先繪製大球佔的比例*/
        piePaint.setColor(mBigBallColor);
        /*The arc is drawn clockwise. An angle of 0 degrees correspond to the
        * geometric angle of 0 degrees (3 o'clock on a watch.)*/
        /*drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint)*/
        /*繪製大球的扇形圖,float startAngle起始角度的0度的位置在3點鐘方向
        * 因此大球的扇形圖要從12點鐘開始繪製,所以起始角度為270度*/
        canvas.drawArc(rectf, 270, 360 * percent, true, piePaint);
        /*換種顏色,開始繪製小球佔的餅狀圖*/
        piePaint.setColor(mSmallBallColor);
        /*起始角度就是12點鐘加上360度乘以大球佔的比例,12點鐘轉換為起始角度為270度*/
        canvas.drawArc(rectf, 270 + 360 * percent, 360 - 360 * percent, true, piePaint);
        /*顏色更改為大球的顏色*/
        piePaint.setColor(mBigBallColor);
        /*繪製上邊的小方塊,也就是大球的方塊*/
        canvas.drawRect(width * 2 / 5 - halfSmallRec, height* 23/ 60 - halfSmallRec, width * 2 / 5 + halfSmallRec, height *23/ 60 + halfSmallRec, piePaint);
        /*更改畫筆顏色為小球顏色*/
        piePaint.setColor(mSmallBallColor);
        /*繪製下邊的小方塊即小球的小方塊*/
        canvas.drawRect(width * 2 / 5 - halfSmallRec, height * 37 / 60 - halfSmallRec, width * 2 / 5 + halfSmallRec, height * 37 / 60 + halfSmallRec, piePaint);
        /*開始繪製文字,先設定文字顏色*/
        textPaint.setColor(getResources().getColor(typedValue.resourceId));
        /*設定問題大小*/
        textPaint.setTextSize(textSize);
        /*大球數量*/
        String strBig = strBigBallName + mBigBallNumber;
        /*測量文字寬度*/
        float textBigWidth =textPaint.measureText(strBig);
        Paint.FontMetrics fontMetrics=textPaint.getFontMetrics();
        /*繪製上邊大球數量*/
        canvas.drawText(strBig, width * 9 / 20 + textBigWidth / 2, height *23/ 60 - fontMetrics.top / 3, textPaint);
        /*小球數量*/
        String strSmall = strSmallBallName + mSmallBallNumber;
        /*測量文字寬度*/
        float textUnderWidth=textPaint.measureText(strSmall);
        /*繪製下邊的小球數量*/
        canvas.drawText(strSmall,width*9/20+textUnderWidth/2,height*37/60-fontMetrics.top/3,textPaint);
        /*更改畫筆顏色,開始繪製百分比*/
        textPaint.setColor(getResources().getColor(R.color.half_transparent));
        String strBigPercent =" ("+ mPercentBigBall +")";
        /*測量大球百分比文字寬度*/
        float bigPercent =textPaint.measureText(strBigPercent);
        /*drawText(String text, float x, float y, Paint paint)
        * 繪製文字的API,四個引數分別是文字內容,起始繪製x座標,起始繪製y座標,畫筆
        * 以為設定了居中繪製,因此穿進去的xy座標為文字的中心點*/
        canvas.drawText(strBigPercent, width * 9 / 20+ textBigWidth + bigPercent /2, height*23 / 60-fontMetrics.top*1/3, textPaint);
        /*同樣的道理繪製小球的百分比*/
        String strSmallPercent =" ("+ mPercentSmallBall +")";
        float smallPercent =textPaint.measureText(strSmallPercent);
        canvas.drawText(strSmallPercent,width*9/20+textUnderWidth+ smallPercent /2,height*37/60-fontMetrics.top/3,textPaint);
    }
    public void setPercent(float percent1){
        this.percent =percent1;
        invalidate();
    }
    public void setColor(int mBigBallColor,int mSmallBallColor){
        this.mBigBallColor =mBigBallColor;
        this.mSmallBallColor =mSmallBallColor;
        invalidate();
    }

    public void setOverRunner(String bigPecent, String smallPercent, int big, int small,
                              int bigColor, int smallColor){
        this.mPercentBigBall = bigPecent;
        this.mPercentSmallBall = smallPercent;
        this.mBigBallNumber = big;
        this.mSmallBallNumber = small;
        this.mBigBallColor = bigColor;
        this.mSmallBallColor = smallColor;
        invalidate();
    }
}



相關文章