android实现饼状图

package com.vanke.easysale.widget.chart;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.View;

import com.vanke.IntegratedPlatform.manager.R;
import com.vanke.easysale.util.DensityUtil;

import java.util.ArrayList;

/**
 * 饼状图
 * Created by rantao on 2017/8/26.
 */

public class PieChartView extends View {

    private int mWidth; // 控件宽度

    private int mHeight; // 控件高度

    private int mOuterRadius; // 外圆半径

    private int mHoleRadius; // 内圆半径

    private Paint mPaint; // 画笔

    private int[] percentText = {}; // 百分比

    private String[] mTexts = {}; // 线条上得文本

    private int[] mColors = new int[]{getResources().getColor(R.color.color_e62e3d),
            getResources().getColor(R.color.color_ffd633),
            getResources().getColor(R.color.color_e5737c),
            getResources().getColor(R.color.color_991f29),
            getResources().getColor(R.color.color_ff0015)
    };

    private int mCenterX; // 圆点X坐标

    private int mCenterY; // 圆点Y坐标

    private float mStartAngle = -90; // 圆弧开始角度

    private ArrayList<PiePoint> mPiePoints = new ArrayList<>();

    private int sumTextSize;

    private String sum = "";

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

    public PieChartView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mCenterX = mWidth / 2;
        mCenterY = mHeight / 2;
        drawArc(canvas);
        drawTextForHoleCenter(canvas);
        drawLine(canvas);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = measure(widthMeasureSpec);
        int height = measure(heightMeasureSpec);
        setMeasuredDimension(width, height);
        updateDimensions(width, height);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        updateDimensions(w, h);
    }

    private void updateDimensions(int width, int height) {
        this.mWidth = width;
        this.mHeight = height;
    }

    private int measure(int measureSpec) {
        int result = 0;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);
        switch (mode) {
            case MeasureSpec.EXACTLY:
                result = size;
                break;
            case MeasureSpec.AT_MOST:
                result = size;
                break;
            case MeasureSpec.UNSPECIFIED:
                break;
            default:
                break;
        }
        return result;
    }

    public void setSum(String sum) {
        this.sum = sum;
    }

    public void setTexts(String[] mTexts) {
        this.mTexts = mTexts;
    }

    public void setPercentText(int[] percentText) {
        this.percentText = percentText;
        invalidate();
    }

    /**
     * 初始化
     */

    private void init() {
        mOuterRadius = DensityUtil.dip2px(getContext(), 63);
        mHoleRadius = DensityUtil.dip2px(getContext(), 38);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        sumTextSize = getResources().getDimensionPixelSize(R.dimen.textsize_18sp);
    }

    /**
     * 画圆弧
     *
     * @param canvas
     */

    private void drawArc(Canvas canvas) {
        if (null != mPiePoints && mPiePoints.size() > 0) {
            mPiePoints.clear();
        }
        int startX = mCenterX - mOuterRadius;
        int endX = mCenterX + mOuterRadius;
        int startY = mCenterY - mOuterRadius;
        int endY = mCenterY + mOuterRadius;
        if (mStartAngle != -90) {
            mStartAngle = -90;
        }
        for (int i = 0; i < percentText.length; i++) {
            mPaint.setColor(mColors[i]);
            double ratio = ((double) percentText[i] / 100);
            float endAngle = (float) (ratio * 360);

            PiePoint piePoint = new PiePoint();
            piePoint.startAngle = mStartAngle;
            piePoint.endAngle = mStartAngle + endAngle;
            mPiePoints.add(piePoint);

            canvas.drawArc(new RectF(startX, startY, endX, endY), mStartAngle, endAngle - 1, true, mPaint);
            mStartAngle = mStartAngle + endAngle; // 下一个开始角度

            // 绘制阴影圆心部分
            int left = mCenterX - mHoleRadius;
            int right = mCenterX + mHoleRadius;
            int top = mCenterY - mHoleRadius;
            int bottom = mCenterY + mHoleRadius;
            Bitmap centerBitmapWithShadow = BitmapFactory.decodeResource(getResources(), R.drawable.ic_piechart_shadow);
            canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
            canvas.drawBitmap(centerBitmapWithShadow, null, new RectF(left, top, right, bottom), mPaint);
        }

    }

    /**
     * 绘制线条
     *
     * @param canvas
     */

    private void drawLine(Canvas canvas) {
        for (int i = 0; i < mPiePoints.size(); i++) {
            float centerAngle = (mPiePoints.get(i).startAngle + mPiePoints.get(i).endAngle) / 2;

            /**
             * 分四个象限和四个坐标轴进行判断
             */

            if (centerAngle > 0 && centerAngle < 90) {
                drawBreakLine(canvas, i, 1);
            } else if (centerAngle > 90 && centerAngle < 180) {
                drawBreakLine(canvas, i, 2);
            } else if (centerAngle > 180 && centerAngle < 270) {
                drawBreakLine(canvas, i, 3);
            } else if ((centerAngle > 270 && centerAngle < 360) || (centerAngle > -90 && centerAngle < 0)) {
                drawBreakLine(canvas, i, 4);
            } else if (centerAngle == 0) {
                drawBreakLine(canvas, i, 5);
            } else if (centerAngle == 90) {
                drawBreakLine(canvas, i, 6);
            } else if (centerAngle == 180) {
                drawBreakLine(canvas, i, 7);
            } else if (centerAngle == 270) {
                drawBreakLine(canvas, i, 8);
            }
        }
    }

    private void drawBreakLine(Canvas canvas, int position, int condition) {
        float centerAngle = (mPiePoints.get(position).startAngle + mPiePoints.get(position).endAngle) / 2;
        int xInArc = 0; // 圆弧中心在圆弧上的X坐标
        int yInArc = 0; // 圆弧中心在圆弧上的Y坐标
        int breakX = 0; // 拐点X坐标
        int breakY = 0; // 拐点Y坐标
        int lineEndX = 0; // 横线结束X坐标
        int lineEndY = 0; // 横线结束Y坐标
        float arcNum;
        mPaint.setColor(mColors[position]);
        switch (condition) {
            case 1:
                arcNum = (float) (Math.PI / 180 * centerAngle);
                xInArc = (int) (mCenterX + (Math.cos(arcNum) * mOuterRadius));
                yInArc = (int) (mCenterY + (Math.sin(arcNum) * mOuterRadius));
                breakX = xInArc + DensityUtil.dip2px(getContext(), 5);
                breakY = yInArc + DensityUtil.dip2px(getContext(), 5);
                lineEndX = breakX + DensityUtil.dip2px(getContext(), 70);
                lineEndY = breakY;
                canvas.drawLine(xInArc, yInArc, breakX, breakY, mPaint);
                canvas.drawLine(breakX, breakY, lineEndX, lineEndY, mPaint);
                canvas.drawCircle(lineEndX, lineEndY, 5, mPaint);

                drawTextOnLine(canvas, position, xInArc, breakY, lineEndX);
                drawTextForEdge(canvas, position, condition, lineEndX + DensityUtil.dip2px(getContext(), 10), lineEndY);
                break;
            case 2:
                arcNum = (float) (Math.PI / 180 * (centerAngle - 90));
                xInArc = (int) (mCenterX - Math.sin(arcNum) * mOuterRadius);
                yInArc = (int) (mCenterY + Math.cos(arcNum) * mOuterRadius);
                breakX = xInArc - DensityUtil.dip2px(getContext(), 5);
                breakY = yInArc + DensityUtil.dip2px(getContext(), 5);
                lineEndX = breakX - DensityUtil.dip2px(getContext(), 70);
                lineEndY = breakY;
                canvas.drawLine(xInArc, yInArc, breakX, breakY, mPaint);
                canvas.drawLine(breakX, breakY, lineEndX, lineEndY, mPaint);
                canvas.drawCircle(lineEndX, lineEndY, 5, mPaint);

                drawTextOnLine(canvas, position, xInArc, breakY, lineEndX);
                drawTextForEdge(canvas, position, condition, lineEndX - DensityUtil.dip2px(getContext(), 10), lineEndY);
                break;
            case 3:
                arcNum = (float) (Math.PI / 180 * (centerAngle - 180));
                xInArc = (int) (mCenterX - Math.cos(arcNum) * mOuterRadius);
                yInArc = (int) (mCenterY - Math.sin(arcNum) * mOuterRadius);
                breakX = xInArc - DensityUtil.dip2px(getContext(), 5);
                breakY = yInArc - DensityUtil.dip2px(getContext(), 5);
                lineEndX = breakX - DensityUtil.dip2px(getContext(), 70);
                lineEndY = breakY;
                canvas.drawLine(xInArc, yInArc, breakX, breakY, mPaint);
                canvas.drawLine(breakX, breakY, lineEndX, lineEndY, mPaint);
                canvas.drawCircle(lineEndX, lineEndY, 5, mPaint);

                drawTextOnLine(canvas, position, xInArc, breakY, lineEndX);
                drawTextForEdge(canvas, position, condition, lineEndX - DensityUtil.dip2px(getContext(), 10), lineEndY);
                break;
            case 4:
                arcNum = (float) (Math.PI / 180 * (centerAngle - 270));
                xInArc = (int) (mCenterX + Math.sin(arcNum) * mOuterRadius);
                yInArc = (int) (mCenterY - Math.cos(arcNum) * mOuterRadius);
                breakX = xInArc + DensityUtil.dip2px(getContext(), 5);
                breakY = yInArc - DensityUtil.dip2px(getContext(), 5);
                lineEndX = breakX + DensityUtil.dip2px(getContext(), 70);
                lineEndY = breakY;
                canvas.drawLine(xInArc, yInArc, breakX, breakY, mPaint);
                canvas.drawLine(breakX, breakY, lineEndX, lineEndY, mPaint);
                canvas.drawCircle(lineEndX, lineEndY, 5, mPaint);

                drawTextOnLine(canvas, position, xInArc, breakY, lineEndX);
                drawTextForEdge(canvas, position, condition, lineEndX + DensityUtil.dip2px(getContext(), 10), lineEndY);
                break;
            case 5: // 0度
                xInArc = mCenterX + mOuterRadius;
                yInArc = mCenterY;
                lineEndX = xInArc + DensityUtil.dip2px(getContext(), 70);
                lineEndY = yInArc;
                breakY = yInArc;
                canvas.drawLine(xInArc, yInArc, lineEndX, lineEndY, mPaint);
                canvas.drawCircle(lineEndX, lineEndY, 5, mPaint);

                drawTextOnLine(canvas, position, xInArc, breakY, lineEndX);
                drawTextForEdge(canvas, position, condition, lineEndX, lineEndY);
                break;
            case 6: // 90度
                xInArc = mCenterX;
                yInArc = mCenterY + mOuterRadius;
                breakX = xInArc;
                breakY = yInArc + DensityUtil.dip2px(getContext(), 10);
                lineEndX = xInArc + DensityUtil.dip2px(getContext(), 70);
                lineEndY = breakY;
                canvas.drawLine(xInArc, yInArc, breakX, breakY, mPaint);
                canvas.drawLine(breakX, breakY, lineEndX, lineEndY, mPaint);
                canvas.drawCircle(lineEndX, lineEndY, 5, mPaint);

                drawTextOnLine(canvas, position, xInArc, breakY, lineEndX);
                drawTextForEdge(canvas, position, condition, lineEndX, lineEndY);
                break;
            case 7: // 180度
                xInArc = mCenterX - mOuterRadius;
                yInArc = mCenterY;
                lineEndX = xInArc - DensityUtil.dip2px(getContext(), 70);
                lineEndY = yInArc;
                breakY = yInArc;
                canvas.drawLine(xInArc, yInArc, lineEndX, lineEndY, mPaint);
                canvas.drawCircle(lineEndX, lineEndY, 5, mPaint);

                drawTextOnLine(canvas, position, xInArc, breakY, lineEndX);
                drawTextForEdge(canvas, position, condition, lineEndX, lineEndY);
                break;
            case 8: // 270度
                xInArc = mCenterX;
                yInArc = mCenterY - mOuterRadius;
                breakX = xInArc;
                breakY = yInArc - DensityUtil.dip2px(getContext(), 10);
                lineEndX = breakX + DensityUtil.dip2px(getContext(), 70);
                lineEndY = breakY;
                canvas.drawLine(xInArc, yInArc, breakX, breakY, mPaint);
                canvas.drawLine(breakX, breakY, lineEndX, lineEndY, mPaint);
                canvas.drawCircle(lineEndX, lineEndY, 5, mPaint);

                drawTextOnLine(canvas, position, xInArc, breakY, lineEndX);
                drawTextForEdge(canvas, position, condition, lineEndX, lineEndY);
                break;
            default:
                break;
        }
    }

    private void drawTextForHoleCenter(Canvas canvas) {
        if (percentText.length != 0) {
            /**
             * 绘制总数动态文本
             */

            int left = mCenterX - DensityUtil.dip2px(getContext(), 10);
            int right = mCenterX + DensityUtil.dip2px(getContext(), 10);
            int top = mCenterY + DensityUtil.dip2px(getContext(), 5);
            int bottom = mCenterY + DensityUtil.dip2px(getContext(), 15);
            Rect rect = new Rect(left, top, right, bottom);
            Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
            int baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2;
            mPaint.setTextAlign(Paint.Align.CENTER);
            sumTextSize = getResources().getDimensionPixelSize(R.dimen.textsize_18sp);
            mPaint.setTextSize(sumTextSize);
            mPaint.setColor(ContextCompat.getColor(getContext(), R.color.color_333333));
            canvas.drawText(sum, rect.centerX(), baseline, mPaint);

            /**
             * 绘制"总数"静态文本
             */
            left = mCenterX - DensityUtil.dip2px(getContext(), 7);
            right = mCenterX + DensityUtil.dip2px(getContext(), 7);
            top = mCenterY - DensityUtil.dip2px(getContext(), 13);
            bottom = mCenterY - DensityUtil.dip2px(getContext(), 3);
            rect = new Rect(left, top, right, bottom);
            baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2;
            mPaint.setTextAlign(Paint.Align.CENTER);
            sumTextSize = getResources().getDimensionPixelSize(R.dimen.textsize_12sp);
            mPaint.setTextSize(sumTextSize);
            mPaint.setColor(ContextCompat.getColor(getContext(), R.color.color_999999));
            canvas.drawText("总数", rect.centerX(), baseline, mPaint);
        }
    }

    /**
     * 绘制线条上的文本
     *
     * @param canvas
     */

    private void drawTextOnLine(Canvas canvas, int position, int startX, int startY, int endX) {
        int startYTmp =  startY - DensityUtil.dip2px(getContext(), 10);
        int endYTmp = startY - DensityUtil.dip2px(getContext(), 5);
        Rect rect = new Rect(startX, startYTmp, endX, endYTmp);
        Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
        int baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2;
        mPaint.setTextAlign(Paint.Align.CENTER);
        sumTextSize = getResources().getDimensionPixelSize(R.dimen.textsize_10sp);
        mPaint.setTextSize(sumTextSize);
        mPaint.setColor(ContextCompat.getColor(getContext(), R.color.color_999999));
        canvas.drawText(mTexts[position], rect.centerX(), baseline, mPaint);
    }

    /**
     * 绘制线条边缘文本
     *
     * @param canvas
     */

    private void drawTextForEdge(Canvas canvas, int position, int codition, int edgeX, int centerY) {
        Rect rect = null;
        switch (codition) {
            case 1:
                rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5),
                        edgeX + DensityUtil.dip2px(getContext(), 10), centerY + DensityUtil.dip2px(getContext(), 5));
                break;
            case 2:
                rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5),
                        edgeX - DensityUtil.dip2px(getContext(), 10), centerY + DensityUtil.dip2px(getContext(), 5));
                break;
            case 3:
                rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5),
                        edgeX - DensityUtil.dip2px(getContext(), 10), centerY + DensityUtil.dip2px(getContext(), 5));
                break;
            case 4:
                rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5),
                        edgeX + DensityUtil.dip2px(getContext(), 10), centerY + DensityUtil.dip2px(getContext(), 5));
                break;
            case 5: // 0度
                rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5),
                        edgeX + DensityUtil.dip2px(getContext(), 30), centerY + DensityUtil.dip2px(getContext(), 5));
                break;
            case 6: // 90度
                rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5),
                        edgeX + DensityUtil.dip2px(getContext(), 30), centerY + DensityUtil.dip2px(getContext(), 5));
                break;
            case 7: // 180度
                rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5),
                        edgeX - DensityUtil.dip2px(getContext(), 30), centerY + DensityUtil.dip2px(getContext(), 5));
                break;
            case 8: // 270度
                rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5),
                        edgeX + DensityUtil.dip2px(getContext(), 30), centerY + DensityUtil.dip2px(getContext(), 5));
                break;
            default:

                break;
        }
        Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
        int baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2;
        mPaint.setTextAlign(Paint.Align.CENTER);
        sumTextSize = getResources().getDimensionPixelSize(R.dimen.textsize_12sp);
        mPaint.setTextSize(sumTextSize);
        mPaint.setColor(ContextCompat.getColor(getContext(), R.color.color_333333));
        String percent = percentText[position] + "%";
        canvas.drawText(percent, rect.centerX(), baseline, mPaint);
    }

    class PiePoint {
        float startAngle;
        float endAngle;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值