自定义饼状图控件PieView

本篇参考:GcsSloop的安卓自定义View进阶-Canvas之绘制图形


这里写图片描述

一、分析如上饼状图,所需要得信息如下

  1. 各块的颜色
  2. 所有块量得总和
  3. 各个块得量占总量的百分比,并通过百分比得到各个块所占扇形的弧度
  4. 第一个块得起始角度
  5. 该 View 控件的宽高及位置

二、具体控件逻辑

  1. javabean

    public class PieData {
        // 用户操作数据
        private String name;        // 名字
        private float value;        // 数值
        private float percentage;   // 百分比
    
        // 非用户操作数据
        private int color = 0;      // 颜色
        private float angle = 0;    // 角度
    
        public PieData(String name, float value) {
            this.name = name;
            this.value = value;
        }
    
        ... // set/get省略
    }
  2. 自定义PieView

    public class PieView extends View {
        // 1. 各块的颜色
        private int[] mColors = {0xFFCCFF00, 0xFF6495ED, 0xFFE32636, 0xFF800000, 0xFF808000, 0xFFFF8C69, 0xFF808080, 0xFFE6B800, 0xFF7CFC00};
        // 2. 第一块的初始角度
        private float mStartAngle = 180;
        // 数据集合
        private ArrayList<PieData> mDatas;
        // 控件宽高
        private int mWidth, mHeight;
        // 画笔
        private Paint mPaint = new Paint();
    
        public PieView(Context context) {
            this(context, null);
        }
    
        public PieView(Context context, AttributeSet attrs) {
            super(context, attrs);
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setAntiAlias(true);
        }
    
        // 记录当前View控件的宽高
        @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            mWidth = w;
            mHeight = h;
        }
    
        // 设置起始角度并刷新界面
        public void setStartAngle(int mStartAngle) {
            this.mStartAngle = mStartAngle;
            invalidate();
        }
    
        // 设置数据并刷新界面
        public void setData(ArrayList<PieData> mData) {
            this.mDatas = mData;
            initData(mData);
            invalidate();
        }
    
        // 饼状图中数据的处理
        float sumValue = 0;       // 所有块的数据总量
        float piePercentage = 0;  // 各块占数据总量的百分比
        float sumAngle = 0;       // 所有块占的总扇形角度
        float pieAngle = 0;       // 各块占的扇形角度
        private void initData(ArrayList<PieData> mDatas) {
            // 判空
            if (null == mDatas || mDatas.size() == 0) {
                return;
            }
    
            for (int i = 0; i < mDatas.size(); i++) {
                PieData pie = mDatas.get(i);
    
                // 1. 设置各块颜色
                int j = i % mColors.length;
                pie.setColor(mColors[j]);
    
                // 2. 统计所有块的数据总量
                sumValue += pie.getValue();
    
                // 3. 计算各块量占总量的百分比
                piePercentage = pie.getValue() / sumValue;
    
                // 4. 通过各块量的占比计算所占扇形角度
                pieAngle = piePercentage * 360;
    
                pie.setPercentage(piePercentage);
                pie.setAngle(pieAngle);
                sumAngle += pieAngle;
            }
        }
    
        @Override protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            // 判空
            if (null == mDatas || mDatas.size() == 0) {
                return;
            }
    
            // 记录当前起始角度
            float currentStartAngle = mStartAngle;
            // 将画布坐标原点移动到中心
            canvas.translate(mWidth / 2, mHeight / 2);
            // 饼状图半径
            float r = (float) (Math.min(mWidth, mHeight) / 2 * 0.8);
            // 确定饼状图绘制的区域
            RectF rect = new RectF(-r, -r, r, r);
    
            for (int i = 0; i < mDatas.size(); i++) {
                PieData pie = mDatas.get(i);
                mPaint.setColor(pie.getColor());
                canvas.drawArc(rect, currentStartAngle, pie.getAngle(), true, mPaint);
                currentStartAngle += pie.getAngle();
            }
        }
    }
  3. 针对上述部分代码片的图解

    这里写图片描述

猜你喜欢

转载自blog.csdn.net/itCatface/article/details/76020997