自定义控件View(三)___绘制饼状图

效果图如下:

这里写图片描述

分析:

  1. 计算绘制的每个区域所占比例: drawArc
  2. 计算每个区域角平分线中点的坐标值
  3. 测量文字的宽度和高度,来确定文字开始绘制的位置,即BaseLine的位置

自定义PipeChartView的代码

public class PipeChartView extends View {
    public static final int DEFAULT_RADIUS_LENGTH = 80;
    public static final Point DEFAULT_POSITION = new Point(0, 0);

    private List<ValueColorEntity> data;
    private Point position = DEFAULT_POSITION;
    private int radiusLength = DEFAULT_RADIUS_LENGTH;
    private int radiusColor =Color.WHITE;


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

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(measureWidth(widthMeasureSpec),
                measureHeight(heightMeasureSpec));
        int width = measureWidth(widthMeasureSpec);
        int height = measureHeight(heightMeasureSpec);
        int rect = Math.min(width, height);

        // 计算圆的半径
        radiusLength = (int) ((rect / 2f) * 1.0);

        // 确定圆中心位置
        position = new Point((int) (width / 2f), (int) (height / 2f));
    }

    private int measureWidth(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) { //match_parent || 固定值
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) { //wrap_content
            result = Math.min(result, specSize);
        }
        return result;
    }

    private int measureHeight(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(result, specSize);
        }
        return result;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawCircle(canvas);//画圆边
        drawArc(canvas); // 画饼状区域
    }

    private void drawCircle(Canvas canvas) {
        Paint mPaintCircleBorder = new Paint();
        mPaintCircleBorder.setColor(Color.WHITE);
        mPaintCircleBorder.setStyle(Paint.Style.STROKE);
        mPaintCircleBorder.setStrokeWidth(1);
        mPaintCircleBorder.setAntiAlias(true);
        canvas.drawCircle(position.x, position.y, radiusLength, mPaintCircleBorder);
    }

    private void drawArc(Canvas canvas) {
        if (null != data) {
            float sum = 0;
            for (int i = 0; i < data.size(); i++) {
                sum = sum + data.get(i).getValue(); //算出总和
            }

            Paint mPaintFill = new Paint();
            mPaintFill.setStyle(Paint.Style.FILL);
            mPaintFill.setAntiAlias(true);

            Paint mPaintBorder = new Paint();
            mPaintBorder.setStyle(Paint.Style.STROKE);
            mPaintBorder.setColor(radiusColor);
            mPaintBorder.setAntiAlias(true);

            int offset = -90;//从竖直方向顺时针开始绘制
            drawEveryArc(canvas, sum, mPaintFill, offset);

            // 绘制显示在每个区域上方的文字
            drawText(canvas, sum, mPaintFill);
        }
    }

    private void drawText(Canvas canvas, float sum, Paint mPaintFill) {
        float sumvalue = 0f;
        for (ValueColorEntity e : data) {
            float value = e.getValue();
            sumvalue = sumvalue + value;
            float rate = (sumvalue - value / 2) / sum;
            mPaintFill.setColor(Color.BLUE);

            // 确定每个区域所占的比例
            int percentage = (int) ((value / sum * 10000) / 100f);

            //确定每个区域角平分线的中点的坐标
            float offsetX = (float) (position.x - radiusLength * 0.5
                    * Math.sin(rate * -2 * Math.PI));
            float offsetY = (float) (position.y - radiusLength * 0.5
                    * Math.cos(rate * -2 * Math.PI));

            //设置绘制画笔样式
            Paint mPaintFont = new Paint();
            mPaintFont.setColor(Color.WHITE);
            mPaintFont.setTextSize(32);
            mPaintFont.setAntiAlias(true);


            float realx = 0;
            float realy = 0;

            // 确定文字绘制的起始点BaseX的坐标= 中心点X坐标-文字的宽度/2
            if (offsetX <= position.x) {
                realx = offsetX - mPaintFont.measureText(String.valueOf(percentage)) / 2;
            } else if (offsetX > position.x) {
                realx = offsetX - mPaintFont.measureText(String.valueOf(percentage)) / 2;
            }

            //确定文字绘制的BaseY的坐标: 此处粗略计算
            if (offsetY >= position.y) {
                if (value / sum < 0.2f) {
                    realy = offsetY + 10;
                } else {
                    realy = offsetY + 5;
                }
            } else if (offsetY < position.y) {
                if (value / sum < 0.2f) {
                    realy = offsetY - 10;
                } else {
                    realy = offsetY + 5;
                }
            }


            if (percentage == 100) {
                canvas.drawText(String.valueOf(100) + "%", position.x - 
                        mPaintFont.measureText(100 + "") / 2, position.y, mPaintFont);
            }

            if (percentage != 0 && percentage != 100) {
                canvas.drawText(String.valueOf(percentage) + "%", realx,
                        realy + 12, mPaintFont);
            }
        }
    }

    private void drawEveryArc(Canvas canvas, float sum, Paint mPaintFill, int offset) {
        // 遍历data集合. 绘制出每一份区域
        for (int j = 0; j < data.size(); j++) {
            ValueColorEntity e = data.get(j);

            // 获取设置的画笔颜色
            mPaintFill.setColor(e.getColor());

            //确定绘制的矩形范围
            RectF oval = new RectF(position.x - radiusLength, position.y - radiusLength,
                    position.x + radiusLength, position.y + radiusLength);
            //计算每个区域扫过的角度
            int sweep = Math.round(e.getValue() / sum * 360f);
            //绘制区域
            canvas.drawArc(oval, offset, sweep, true, mPaintFill);
            offset = offset + sweep;
        }
    }

    public void setData(List<ValueColorEntity> list) {
        this.data = list;
        invalidate();
    }}

用于设置数据和颜色的bean对象:

public class ValueColorEntity {
    private int value;

    private int Color;

    public ValueColorEntity(int value, int color) {
        this.value = value;
        Color = color;
    }

    public int getValue() {
        return value;
    }

    public int getColor() {
        return Color;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public void setColor(int color) {
        Color = color;
    }
}

四. 使用自定义的控件

  • xml布局:
<com.showdy.widget.PipeChartView
        android:id="@+id/my_arc_progress"
        android:layout_width="190dp"
        android:layout_height="190dp"
        android:layout_marginTop="40dp"/>

*

五.代码引用:

private List<ValueColorEntity> mDatas= new ArrayList<>();
mDatas.add(new ValueColorEntity(complete,getResources().getColor(R.color.my_order_completed)));
mDatas.add(newValueColorEntity(servicing,getResources().getColor(R.color.my_order_handling)));
mDatas.add(new ValueColorEntity(serviced,getResources().getColor(R.color.my_order_handled)));
mDatas.add(new ValueColorEntity(noaccept,getResources().getColor(R.color.my_order_unhandled)));
mPieChart.setData(mDatas);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值