自定義圓形統計圖(靜態)

    最近項目中有這個需求,將總資產的組成以圖形的形態展現出來,所以就寫了個自定義View來實現這個需求。


    其實試下這個思路還是挺簡單的,因爲只需要在onDraw方法中使用畫筆畫出一個又一個的扇形,就能實現這樣的效果。

    以下是我的思路,首先介紹下canvas.drawArc()方法。

    RectF rectF = new RectF(100, 100, 500, 500);
    //繪製扇形
    canvas.drawArc(rectF, startAngle, endAngle, true, paint);

    參數說明:

    rectF:繪製扇形的區域

    startAngle:扇形的開始繪製的角度(是角度值不是弧度值)

    endAngle:扇形繪製結束的角度值

    true:是否從圓心開始畫扇形

    paint:畫筆

    所以實現起來的思路就是:

    通過給定的數據值,也就是一個包含數字的數組,然後算出每個數字的比重,乘上360度,算出每個數字所佔的扇形的角度值,然後通過給不同數字的畫上顏色不同的扇形,當處理完所有的數據後,就可以看到由不同顏色扇形所組成的一個圓,這當然不是我們所想要的,所以在最後,以相同的圓心畫一個白色的圓,當然這個圓的半徑要比剛剛那個彩色的圓的半徑要小,最後剩下的就是我們想要的結果,最後在扇形的中間寫上我們需要的文字即可。

    這個是畫上幾個扇形後的效果。


在中間畫一個白色的圓之後就變成這樣的了


其實這個時候就已經初見成效了。最後加上文字就好了。


最後提供自定義的控件。

SelfStatistics.java

package com.cretin.testprogress.views;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

/**
* Created by cretin on 16/6/23.
*/
public class SelfStatistics extends View {
   private Paint paint;
   //對外提供注入數據的變量
   private float[] datas;
   //自定義view內部存儲數據信息
   private List<Infos> listDatas = new ArrayList<>();
   //默認統計圖的顏色配置 如果數據大於4 則顏色輪詢
   private String colorRes[] = new String[]{"#fdb128", "#4a90e2", "#89c732", "#f46950"};
   private int mPanelWidth;

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

   private void init() {
       paint = new Paint();
   }

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

   public SelfStatistics(Context context, AttributeSet attrs, int defStyleAttr) {
       super(context, attrs, defStyleAttr);
       init();
   }

   @TargetApi(Build.VERSION_CODES.LOLLIPOP)
   public SelfStatistics(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
       super(context, attrs, defStyleAttr, defStyleRes);
       init();
   }

   public float[] getDatas() {
       return datas;
   }

   public void startDraw() {
       invalidate();
   }

   public void setDatas(float[] datas) {
       this.datas = datas;
   }

   @Override
   protected void onDraw(Canvas canvas) {
       super.onDraw(canvas);
       if (datas != null && datas.length > 0) {
           calculateDatas();
           //獲取圓心的x座標
           int center = mPanelWidth / 2;
           //圓環的半徑
           int radius = center - 10;
           //消除鋸齒
           paint.setAntiAlias(true);
           //給外圈設置樣式
           paint.setStyle(Paint.Style.FILL_AND_STROKE);
           //設置StrokeWidth
           paint.setStrokeWidth(20);
           //給外圈設置顏色
           paint.setColor(Color.WHITE);
           //畫最外層的圈
           canvas.drawCircle(center, center, radius, paint);
           //設置進度的顏色
           for (Infos infos : listDatas) {
           //定義一個RectF類
               paint.setColor(Color.parseColor(infos.getColor()));
               RectF rectF = new RectF(center - radius, center - radius, center + radius, center + radius);
               //繪製扇形
               canvas.drawArc(rectF, infos.getStartAngle(), infos.getEndAngle(), true, paint);
           }
            //畫最外層的圈
           paint.setColor(Color.WHITE);
           canvas.drawCircle(center, center, radius - 50, paint);

           drawTexts(canvas, center);
       }
   }

   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
       int widthSize = MeasureSpec.getSize(widthMeasureSpec);
       int widthMode = MeasureSpec.getMode(widthMeasureSpec);

       int heightSize = MeasureSpec.getSize(heightMeasureSpec);
       int heightMode = MeasureSpec.getMode(heightMeasureSpec);

       int width = Math.min(widthSize, heightSize);
       if (widthMode == MeasureSpec.UNSPECIFIED) {
           width = heightSize;
       } else if (heightMode == MeasureSpec.UNSPECIFIED) {
           width = widthSize;
       }
       setMeasuredDimension(width, width);
   }

   @Override
   protected void onSizeChanged(int w, int h, int oldw, int oldh) {
       super.onSizeChanged(w, h, oldw, oldh);
       mPanelWidth = Math.min(w,h);
   }

   private void drawTexts(Canvas canvas, int center) {
       float total = 0;
       for (int i = 0; i < datas.length; i++) {
           total += datas[i];
       }
       String totalStr = total + "元";
       paint.setStrokeWidth(2);
       //設置進度扇形的樣式
       paint.setStyle(Paint.Style.FILL);
       //設置文字的大小
       paint.setTextSize(35);
       int widthStr1 = (int) paint.measureText("總資產");
       int widthStr2 = (int) paint.measureText(totalStr);
       paint.setColor(Color.parseColor("#333333"));
       float baseX = center - widthStr1 / 2;
       float baseY = center + 20 / 4;
       Paint.FontMetrics fontMetrics = paint.getFontMetrics();
       float fontTotalHeight = fontMetrics.bottom - fontMetrics.top;
       float offY = fontTotalHeight / 2 - fontMetrics.bottom - 30;
       float newY = baseY + offY;
       canvas.drawText("總資產", baseX, newY, paint);

       paint.setColor(Color.parseColor("#fc561f"));
       float baseX1 = center - widthStr2 / 2;
       float baseY1 = center + 20 / 4;
       Paint.FontMetrics fontMetrics1 = paint.getFontMetrics();
       float fontTotalHeight1 = fontMetrics1.bottom - fontMetrics1.top;
       float offY1 = fontTotalHeight1 / 2 - fontMetrics1.bottom + 30;
       float newY1 = baseY1 + offY1;
       canvas.drawText(totalStr, baseX1, newY1, paint);
   }

   //爲繪畫做基本的計算
   private void calculateDatas() {
       float total = 0;
       float tempAngle = 270;
       //計算出總數
       for (int i = 0; i < datas.length; i++) {
           total += datas[i];
       }
       //創建不同的Infos對象
       Infos infos;
       for (int i = 0; i < datas.length; i++) {
           infos = new Infos();
           float currData = datas[i];
           float startAngle = tempAngle;
           float endAngle = (float) (currData * 100 / total * 3.6);
           infos.setStartAngle(startAngle);
           infos.setEndAngle(endAngle);
           infos.setColor(colorRes[i % colorRes.length]);
           tempAngle = endAngle + tempAngle;
           listDatas.add(infos);
       }
   }

   class Infos {
       private float startAngle;
       private float endAngle;
       private String color;

       public String getColor() {
           return color;
       }

       public void setColor(String color) {
           this.color = color;
       }

       public float getStartAngle() {
           return startAngle;
       }

       public void setStartAngle(float startAngle) {
           this.startAngle = startAngle;
       }

       public float getEndAngle() {
           return endAngle;
       }

       public void setEndAngle(float endAngle) {
           this.endAngle = endAngle;
       }
   }
}


最後提供使用的方法:

佈局文件:activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context="com.cretin.testprogress.MainActivity">

   <com.cretin.testprogress.views.SelfStatistics
       android:id="@+id/progress"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content" />
</RelativeLayout>


主函數的調用:

package com.cretin.testprogress;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import com.cretin.testprogress.views.SelfStatistics;

public class MainActivity extends AppCompatActivity {

   private SelfStatistics selfStatistics;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       selfStatistics = (SelfStatistics) findViewById(R.id.progress);
       float datas[] = new float[]{4000,3000,7000,8000};
       selfStatistics.setDatas(datas);
       selfStatistics.startDraw();
   }
}


最後我寫了一個demo,歡迎下載,重在分享,不要積分哦,哈哈

下載地址爲:http://download.csdn.net/detail/u010998327/9557747

發佈了61 篇原創文章 · 獲贊 65 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章