Android自定义View————自定义数据绘制饼状图

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_29675423/article/details/86157808

重写View中的OnDraw()方法,进行统计图的绘制。

绘制基础

  • canvas: 非常重要的类,里面有很多绘制类,画线、画圆、画矩形、画扇形等。同时也是重要的辅助类,辅助进行裁切以及画面的几何变换。
    drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) 绘制图片
    drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint)绘制扇形、弧线等
    drawCircle(float cx, float cy, float radius, Paint paint)绘制圆
    drawColor(int color)画布上色
  • paint:也很重要,算是绘制风格。不只是设置颜色、线条粗心、填充、边框等,还可以设置风格、特效。
    Paint.setStyle(Style style) 设置绘制模式
    Paint.setColor(int color) 设置颜色
    Paint.setStrokeWidth(float width) 设置线条宽度
    Paint.setTextSize(float textSize) 设置文字大小

画布坐标

在 Android 里,每个 View 都有一个自己的坐标系,彼此之间是不影响的。这个坐标系的原点是 View 左上角的那个点;水平方向是 x 轴,右正左负;竖直方向是 y 轴,下正上负。
在这里插入图片描述

获取屏幕中心点坐标:

centerX = getResources().getDisplayMetrics().widthPixels/2;
centerY = getResources().getDisplayMetrics().heightPixels/2;

重写方法onDraw(Canvas canvas)

在这个方法拿到canvas对象,可以进行绘制。

Paint paint = new Paint();
@Override
protected void onDraw(Canvas canvas) {  
    super.onDraw(canvas);
    // 绘制一个圆
    canvas.drawCircle(300, 300, 200, paint);
}

首先,我们需要计算各个数据在饼状图中占的角度,以及我们为各个数据设置的颜色。然后根据角度去绘制相应的扇形,并根据颜色设置绘制的paint。

drawArc() 中left, top, right, bottom 描述的是这个弧形所在的椭圆(圆);startAngle 是弧形的起始角度(x 轴的正向,即正右的方向,是 0 度的位置;顺时针为正角度,逆时针为负角度),sweepAngle 是弧形划过的角度;useCenter 表示是否连接到圆心,如果不连接到圆心,就是弧形,如果连接到圆心,就是扇形。

useCenter 这里需要true

显然我们需要每绘制完一个扇形就要重新计算起始角度。其他的没什么逻辑了。

绘制案例:一个简单的view

本人写了一个简单的view,包括饼状图和图例部分。

定义数据, 数据以及圆心角度数

    private HashMap<String , Float> DataDegree(){
        HashMap<String , Float> data = new HashMap<>();
        data.put("苹果", 30f);
        data.put("西瓜", 41f);
        data.put("香蕉", 59f);
        data.put("脐橙", 80f);
        data.put("菠萝",140f);
        return data;
    }

定义数据颜色

@RequiresApi(api = Build.VERSION_CODES.O)
    private HashMap<String , String> DataColor(){
        HashMap<String , String> data = new HashMap<>();
        data.put("苹果", "#6600ff");
        data.put("西瓜", "#cc00ff");
        data.put("香蕉","#9933ff");
        data.put("脐橙", "#ff9900");
        data.put("菠萝","#9999ff");
        return data;
    }

绘制图例部分

@RequiresApi(api = Build.VERSION_CODES.O)
    private void drawPieChartAnno() {
        HashMap<String , Float> dataDegree = DataDegree();
        HashMap<String , String> dataColor = DataColor();

        int left = 30;
        int right = 150;
        int top = 30;
        int rectHeight = 80;
        int bottom = top+rectHeight;
        int blank = 30;

        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setTextSize(50);
        for(String key : dataDegree.keySet()){
            mPaint.setColor(Color.parseColor(dataColor.get(key)));
            mCanvas.drawRect(left,top,right,bottom,mPaint);
            mPaint.setColor(Color.DKGRAY);
            mCanvas.drawText(key+":"+ new DecimalFormat("#.00").format((dataDegree.get(key)+2)/360*100)+"%",right+blank, bottom ,mPaint);
            //更新边界位置
            top = bottom + blank;
            bottom  = top + rectHeight;
        }
    }

绘制饼状图


    @RequiresApi(api = Build.VERSION_CODES.O)
    private void darwPieChart() {
        HashMap<String , Float> dataDegree = DataDegree();
        HashMap<String , String> dataColor = DataColor();

        int left = centerX - 400;
        int right = centerX + 400;
        int top = centerY +100-400 ;
        int bottom  = centerY +100 +400;

        //根据颜色和度数绘制饼状图
        float startAngle = 2f;
        mPaint.setStyle(Paint.Style.FILL);

        for(String key : dataDegree.keySet()){
            mPaint.setColor(Color.parseColor(dataColor.get(key)));
            mCanvas.drawArc(left,top,right,bottom, startAngle,dataDegree.get(key),true,mPaint);
            startAngle += dataDegree.get(key)+ 2f;
        }
    }

整理代码

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.view.View;

import java.text.DecimalFormat;
import java.util.HashMap;

public class MyDataView extends View {

    private Paint mPaint = new Paint();
    private Canvas mCanvas;

    private int centerX,centerY;

    public MyDataView(Context context) {
        super(context);
    }


    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);

        mCanvas = canvas;
        centerX = getResources().getDisplayMetrics().widthPixels/2;
        centerY = getResources().getDisplayMetrics().heightPixels/3;

        //绘制 饼图
        darwPieChart();

        //绘制图例
        drawPieChartAnno();
    }


    @RequiresApi(api = Build.VERSION_CODES.O)
    private void drawPieChartAnno() {
        HashMap<String , Float> dataDegree = DataDegree();
        HashMap<String , String> dataColor = DataColor();

        int left = 30;
        int right = 150;
        int top = 30;
        int rectHeight = 80;
        int bottom = top+rectHeight;
        int blank = 30;

        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setTextSize(50);
        for(String key : dataDegree.keySet()){
            mPaint.setColor(Color.parseColor(dataColor.get(key)));
            mCanvas.drawRect(left,top,right,bottom,mPaint);
            mPaint.setColor(Color.DKGRAY);
            mCanvas.drawText(key+":"+ new DecimalFormat("#.00").format((dataDegree.get(key)+2)/360*100)+"%",right+blank, bottom ,mPaint);
            //更新边界位置
            top = bottom + blank;
            bottom  = top + rectHeight;
        }
    }


    @RequiresApi(api = Build.VERSION_CODES.O)
    private void darwPieChart() {
        HashMap<String , Float> dataDegree = DataDegree();
        HashMap<String , String> dataColor = DataColor();

        int left = centerX - 400;
        int right = centerX + 400;
        int top = centerY +100-400 ;
        int bottom  = centerY +100 +400;

        //根据颜色和度数绘制饼状图
        float startAngle = 2f;
        mPaint.setStyle(Paint.Style.FILL);

        for(String key : dataDegree.keySet()){
            mPaint.setColor(Color.parseColor(dataColor.get(key)));
            mCanvas.drawArc(left,top,right,bottom, startAngle,dataDegree.get(key),true,mPaint);
            startAngle += dataDegree.get(key)+ 2f;
        }
    }



    private HashMap<String , Float> DataDegree(){
        HashMap<String , Float> data = new HashMap<>();
        data.put("苹果", 30f);
        data.put("西瓜", 41f);
        data.put("香蕉", 59f);
        data.put("脐橙", 80f);
        data.put("菠萝",140f);
        return data;
    }


    @RequiresApi(api = Build.VERSION_CODES.O)
    private HashMap<String , String> DataColor(){
        HashMap<String , String> data = new HashMap<>();
        data.put("苹果", "#6600ff");
        data.put("西瓜", "#cc00ff");
        data.put("香蕉","#9933ff");
        data.put("脐橙", "#ff9900");
        data.put("菠萝","#9999ff");
        return data;
    }
}

使用View

public class CanvasActivity extends AppCompatActivity {

    private MyDataView myDataView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        myDataView = new MyDataView(this);
        setContentView(myDataView);
    }
}

绘制案例进阶:将数据传入View,生成饼状图

上面的View是一个写死的数据源和数据颜色,用户交互性较差。

那么,我们来优化一下我们的View,使得我们可以将数据和View分离,达到给View传递数据,可以控制生成view及样式。

那么,如何给我们的View传递数据呢?
那就是在我们的构造方法中添加我们的数据和颜色。
来看一下代码:

/**
     * constructor
     * @param context
     * @param dataDegree
     * @param dataColor
     */
    public MyDataView(Context context,
                      HashMap<String , Float> dataDegree,
                      HashMap<String , String> dataColor) {
        super(context);
        this.dataDegree = dataDegree;
        this.dataColor = dataColor;
    }

    /**
     * constructor
     * @param context
     * @param dataDegree
     * @param dataColor
     * @param attrs
     */
    public MyDataView(Context context,
                      HashMap<String , Float> dataDegree,
                      HashMap<String , String> dataColor,
                      @Nullable AttributeSet attrs
                      ) {
        super(context, attrs);
        this.dataDegree = dataDegree;
        this.dataColor = dataColor;
    }

    /**
     * constructor
     * @param context
     * @param dataDegree
     * @param dataColor
     * @param attrs
     * @param defStyleAttr
     */
    public MyDataView(Context context,
                      HashMap<String , Float> dataDegree,
                      HashMap<String , String> dataColor,
                      @Nullable AttributeSet attrs,
                      int defStyleAttr
                      ) {
        super(context, attrs, defStyleAttr);
        this.dataDegree = dataDegree;
        this.dataColor = dataColor;
    }

    /**
     * constructor
     * @param context
     * @param dataDegree
     * @param dataColor
     * @param attrs
     * @param defStyleAttr
     * @param defStyleRes
     */
    public MyDataView(Context context, HashMap<String , Float> dataDegree,
                      HashMap<String , String> dataColor,
                      @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes
                      ) {
        super(context, attrs, defStyleAttr, defStyleRes);
        this.dataDegree = dataDegree;
        this.dataColor = dataColor;
    }

同时,为了让我们的统计图适应不同的大小,我们不把其中的数据写死,而是根据其大小进行设置。
另外,我们的数据可以灵活的加入。

   
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);

        mCanvas = canvas;
        mWidth = canvas.getWidth();
        mHeight = canvas.getHeight();
		//定义一个我们的尺寸单位
        mPx = Math.max(mWidth/100, 10);

        //绘制 饼图
        darwPieChart();

        //绘制图例
        drawPieChartAnno();
    }

    /**
     * 绘制图例
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void drawPieChartAnno() {
		//设置绘图参数
        int left = mPx;
        int right = mPx * 6;
        int top = mPx;
        int rectHeight = mPx * 3;
        int bottom = top+rectHeight;
        int blank = mPx;

        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setTextSize(mPx * 2);
        for(String key : dataDegree.keySet()){
            mPaint.setColor(Color.parseColor(dataColor.get(key)));
            mCanvas.drawRect(left,top,right,bottom,mPaint);
            mPaint.setColor(Color.DKGRAY);
            mCanvas.drawText(key+":"+ new DecimalFormat("#.00").format((dataDegree.get(key))/360*100)+"%",right+blank, bottom ,mPaint);
            //更新边界位置
            top = bottom + blank;
            bottom  = top + rectHeight;
        }
    }

    /**
     * 绘制统计图
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void darwPieChart() {

        int centerX = mWidth/2;
        int centerY = mHeight/2;
        int radius = mPx * 20;
        int left = centerX - radius;
        int right = centerX + radius;
        int top = centerY - radius ;
        int bottom  = centerY + radius;

        //根据颜色和度数绘制饼状图
        float startAngle = 0f;
        mPaint.setStyle(Paint.Style.FILL);

        for(String key : dataDegree.keySet()){
        	//绘制饼状图
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setColor(Color.parseColor(dataColor.get(key)));
            mCanvas.drawArc(left,top,right,bottom, startAngle,dataDegree.get(key),true,mPaint);
            //给饼状图添加一个修饰,白边
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(Color.WHITE);
            mCanvas.drawArc(left,top,right,bottom, startAngle,dataDegree.get(key),true,mPaint);
            startAngle += dataDegree.get(key);
        }
    }

然后,使用的时候,我们需要在代码中动态添加这个视图,通过new MyDataView(this, DataDegree(), DataColor())初始化,然后addView(myDataView, params)的方式添加。

 @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    protected void onResume() {
        super.onResume();
        myDataView = new MyDataView(this, DataDegree(), DataColor());
        params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);

        mLny.addView(myDataView, params);
    }

    private HashMap<String , Float> DataDegree(){
        dataDegee.put("餐饮消费", 32f);
        dataDegee.put("文教娱乐", 42f);
        dataDegee.put("服饰美容", 52f);
        dataDegee.put("出行交通", 92f);
        dataDegee.put("其它",142f);
        return dataDegee;
    }


    @RequiresApi(api = Build.VERSION_CODES.O)
    private HashMap<String , String> DataColor(){

        dataColor.put("餐饮消费", "#6600ff");
        dataColor.put("文教娱乐", "#cc00ff");
        dataColor.put("服饰美容","#9933ff");
        dataColor.put("出行交通", "#ff9900");
        dataColor.put("其它","#9999ff");
        return dataColor;
    }

完整代码git地址:https://github.com/DuckGrandfather/GeneratePieChart.git

猜你喜欢

转载自blog.csdn.net/sinat_29675423/article/details/86157808