圆环形百分比统计

此为效果图

参考:http://blog.csdn.NET/u010053224/article/details/51799523

/**
 * Created by ${ITcat} on 2017/3/1.
 *
 * 自定义的圆形饼图控件
 */
public class MyPieChartView extends View {
    private final float density = getResources().getDisplayMetrics().density;
    //饼图之间的间隔的角度
    private final float LR_PADDING = 25 * density;
    //顶部的空间距离
    private final float TOP_PADDING = 25 * density;
    //饼图和下面文字之间的距离
    private final float PIE_TEXT_DIS = 22 * density;
    //上下行文字之间的距离
    private final float TEXT_TEXT_DIS = 15 * density;
    //底部和文字的距离,实际为BOTTOM_DIS+TEXT_TEXT_DIS
    private final float BOTTOM_DIS = 10 * density;
    //标题和值之间的最小距离
    private final float TITLE_VALUE_DIS = 18 * density;

    //每部分的颜色值,默认有10个颜色
    private int[] mColors = new int[]{0xfff5a002,0xfffb5a2f,0xff36bc99,0xff43F90C,0xff181A18,0xffF802F6
                    ,0xff022DF8,0xffECF802,0xff02F8E8,0xffEA0F8E};
    //    private double[] mValues;
    //值转换成角度
    private float[] mAngles;
    //饼图直径
    private float pieR;
    //饼图所占的总的角度
    private float pieAngle;

    private String[] mTitles; //每部分的内容

    private float mTitleSize;
    private float mValueSize;

    private int mTitleColor = 0xFF999999;
    private int mValueColor = 0xFF999999;


    private Paint mPiePaint;
    private Paint mTextPaint;


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

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

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

        mTitleSize = sp2px(12);
        mValueSize = sp2px(12);
        mPiePaint = new Paint();
        mTextPaint = new Paint();
        mTextPaint.setColor(0xff999999);
        mTextPaint.setTextSize(mTitleSize);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int newHeightSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, newHeightSpec);
    }

    /**
     * 重写onDraw方法
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPiePaint.setAntiAlias(true);
        mTextPaint.setAntiAlias(true);
        /**------------------------------无数据时的默认显示--------------------------------*/
        if (mTitles == null || mTitles.length == 0 || isValueEmpty()) {
            mTitles = new String[]{"美利金融","微贷网","团贷网","其他"};
            mValues = new double[] {999,999,999,999};
            mColors = new int[]{0xfff5a002,0xfffb5a2f,0xff36bc99,0xfff7a003};
            int textHeight = getTextHeight("00",Math.max(mTitleSize,mValueSize));
            float r1 = getWidth() - LR_PADDING*2;
            float r2 = getHeight() - TOP_PADDING - PIE_TEXT_DIS - (TEXT_TEXT_DIS+textHeight)*(mTitles.length) - BOTTOM_DIS;
            pieR = Math.min(r1,r2)/2;//为了防止饼图越界,饼图直径选取最小值
            //画矩形,左上右下
            RectF oval = new RectF(0,TOP_PADDING,pieR/2,TOP_PADDING+pieR/2);
            mPiePaint.setStyle(Paint.Style.FILL);
            mAngles = getAngles();

            float startAngle = 0;
            for (int i = 0; i < mAngles.length; i++) {
                mPiePaint.setColor(mColors[i]);
                if (mAngles[i] == 0) continue;;
                canvas.drawArc(oval,startAngle,mAngles[i],true,mPiePaint);
                startAngle += (mAngles[i]);
            }
            /**---画一个遮盖圆在上面形成一个圆环(这里可以修改内圆的大小和圆心坐标)--------------------------------*/
            mPiePaint.setColor(0xFFFFFFFF);
            float cr = (getWidth()<getHeight()?getWidth()/2:getHeight()/2) - LR_PADDING;
            //获取到圆心的坐标,获取到半径和画笔调用画方法(调节小圆的半径可以调节控件的大小)
            canvas.drawCircle(pieR/4,TOP_PADDING+pieR/4,cr/8,mPiePaint);

            /**------------------------------右边的文字,titlevalue--------------------------------*/
            float cr1 = 4 * density;//圆点的半径
            float ctd = 8 * density;//圆点和右边文字的距离
            float titleLen = getMaxTextWidth(mTitles,mTitleSize) + TITLE_VALUE_DIS;
            float len = 2*cr1 + ctd + titleLen + getMaxTextWidth(mTitles,mTitleSize);
            float topDis = TOP_PADDING +TEXT_TEXT_DIS+textHeight;//第一行文字底部和控件顶部的距离
            float cX = (getWidth() - len)/2 + cr1 -20;
            float titleX = cX+cr1+ctd -20;
            float valueX = titleX + titleLen -40;
            setPieContentText();
            /**---------------循环写入内部文字和所占百分比--------------------------------*/
            float yDis = topDis;
            for (int i = 0; i < mTitles.length; i++) {
                mPiePaint.setColor(mColors[i]);
                if (i == 1) {
                    cX = cX + 250;
                    titleX = titleX +250;
                    valueX = valueX +230;
                }

                if (i == 2) {
                    yDis = topDis+60;
                    cX = cX - 250;
                    titleX = titleX -250;
                    valueX = valueX -230;
                }
                if (i == 3) {
                    yDis = topDis+60;
                    cX = cX + 250;
                    titleX = titleX +250;
                    valueX = valueX +230;
                }
                canvas.drawCircle(cX,yDis-textHeight/2,cr1,mPiePaint);
                mTextPaint.setTextSize(mTitleSize);
                mTextPaint.setColor(mTitleColor);
                canvas.drawText(mTitles[i],titleX,yDis,mTextPaint);
                mTextPaint.setColor(mValueColor);
                mTextPaint.setTextSize(mValueSize);
                canvas.drawText("0.00%",valueX,yDis,mTextPaint);
            }
            return;
        }
        else{
            /**------------------------------有数据时的显示--------------------------------*/
            /**------------------------------画饼图--------------------------------*/
            int textHeight = getTextHeight("00",Math.max(mTitleSize,mValueSize));
            float r1 = getWidth() - LR_PADDING*2;
            float r2 = getHeight() - TOP_PADDING - PIE_TEXT_DIS - (TEXT_TEXT_DIS+textHeight)*(mTitles.length) - BOTTOM_DIS;
            pieR = Math.min(r1,r2)/2;//为了防止饼图越界,饼图直径选取最小值
            //画矩形,左上右下
            /**--------控制外圆的圆心,修改距离上的值--------------------------------*/
            RectF oval = new RectF(0,TOP_PADDING-20,pieR/2,TOP_PADDING+pieR/2-20);
            mPiePaint.setStyle(Paint.Style.FILL);
            mAngles = getAngles();

            float startAngle = 0;
            for (int i = 0; i < mAngles.length; i++) {
                mPiePaint.setColor(mColors[i]);
                if (mAngles[i] == 0) continue;;
                canvas.drawArc(oval,startAngle,mAngles[i],true,mPiePaint);
                startAngle += (mAngles[i]);
            }
            /**---画一个遮盖圆在上面形成一个圆环(这里可以修改内圆的大小和圆心坐标)--------------------------------*/
            mPiePaint.setColor(0xFFFFFFFF);
            float cr = (getWidth()<getHeight()?getWidth()/2:getHeight()/2) - LR_PADDING;
            //获取到圆心的坐标,获取到半径和画笔调用画方法(调节小圆的半径可以调节控件的大小)
            /**--------控制内圆的圆心,修改距离上的值--------------------------------*/
            canvas.drawCircle(pieR/4,TOP_PADDING+pieR/4-20,cr/8,mPiePaint);
            /**------------------------------画饼图--------------------------------*/


            /**------------------------------右边的文字,titlevalue--------------------------------*/
            float cr1 = 4 * density;//圆点的半径
            float ctd = 8 * density;//圆点和右边文字的距离
            float titleLen = getMaxTextWidth(mTitles,mTitleSize) + TITLE_VALUE_DIS;
            float len = 2*cr1 + ctd + titleLen + getMaxTextWidth(mTitles,mTitleSize);
            /**---------------控制右边的行高度--------------------------------*/
            float topDis = TOP_PADDING +TEXT_TEXT_DIS+textHeight -20;//第一行文字底部和控件顶部的距离
            float cX = (getWidth() - len)/2 + cr1 -20;
            float titleX = cX+cr1+ctd -10;
            float valueX = titleX + titleLen -30;
            setPieContentText();
            /**---------------循环写入内部文字和所占百分比--------------------------------*/
            float yDis = topDis;
            for (int i = 0; i < mTitles.length; i++) {
                mPiePaint.setColor(mColors[i]);
                if (i == 1) {
                    cX = cX + 250;
                    titleX = titleX +250;
                    valueX = valueX +230;
                }
                if (i == 2) {
                    yDis = topDis+60;
                    cX = cX - 250;
                    titleX = titleX -250;
                    valueX = valueX -230;
                }
                if (i == 3) {
                    yDis = topDis+60;
                    cX = cX + 250;
                    titleX = titleX +250;
                    valueX = valueX +230;
                }
                setData(canvas,cX,yDis,textHeight,cr1,titleX,valueX,i);
            }
        }
    }

    /**
     * 设置饼图左边的文字和圆点
     */
    private void setData(Canvas canvas,float cX,float yDis,float textHeight,float cr1,float titleX,float valueX,int i) {

        canvas.drawCircle(cX,yDis-textHeight/2,cr1,mPiePaint);
        mTextPaint.setTextSize(mTitleSize);
        mTextPaint.setColor(mTitleColor);
        canvas.drawText(mTitles[i],titleX,yDis,mTextPaint);
        mTextPaint.setColor(mValueColor);
        mTextPaint.setTextSize(mValueSize);
        canvas.drawText(percents[i],valueX,yDis,mTextPaint);
    }

    /**
     * 设置每个饼图代表的名字
     * @param titles
     */
    public void setTitles(List<String> titles){
        mTitles = (String[])titles.toArray();
    }

    /**
     * 设置每个饼图代表的名字
     * @param titles
     */
    public void setTitles(String[] titles){
        mTitles = titles;
    }

    /**
     * 设置每个名字代表的值
     * @param values
     */
    public void setValues(List<Double> values){
        mValues = new double[values.size()];
        for(int i=0;i<values.size();i++){
            mValues[i] = values.get(i);
        }
    }
    /**
     * 设置每个名字代表的值
     * @param values
     */
    public void setValues(double[] values){
        mValues = values;
    }
    /**
     * 设置每块饼图的颜色
     * @param colors
     */
    public void setColors(List<Integer> colors){
        mColors = new int[colors.size()];
        for(int i=0;i<colors.size();i++){
            mColors[i] = colors.get(i);
        }
    }
    /**
     * 设置每块饼图的颜色
     * @param colors
     */
    public void setColors(int[] colors){
        mColors = colors;
    }

    /**
     * 设置名字的字体大小
     * @param size
     */
    public void setTitleSize(float size){
        mTitleSize = sp2px(size);
    }

    /**
     * 设置数值的大小
     * @param size
     */
    public void setValueSize(float size){
        mValueSize = sp2px(size);
    }


    private float sp2px(float sp){
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());
    }

    /**
     * 名字的颜色
     * @param titleColor
     */
    public void setTitleColor(int titleColor){
        mTitleColor = titleColor;
    }

    /**
     * 数值的颜色
     * @param valueColor
     */
    public void setValueColor(int valueColor){
        mValueColor = valueColor;
    }



    /**
     * 判断是否有数据
     * @return
     */
    private boolean isValueEmpty() {
        if (mValues == null || mValues.length == 0)
            return true;
        for (double va:mValues) {
            if (va > 0 ) {
                return false;
            }
        }
        return true;
    }

    //获取文本Text的宽度
    private int getTextWidth(String str,float size){
        return getTextRect(str, size).width();
    }
    //获取文本Text的高度
    private int getTextHeight(String str,float size){
        return getTextRect(str, size).height();
    }
    //获取文本Text的矩形
    private Rect getTextRect(String str,float size){
        Rect textBound = new Rect();
        Paint paint = new Paint();
        paint.setTextSize(size);
        paint.getTextBounds(str, 0, str.length(), textBound);
        return textBound;
    }

    /**
     * 获取每个值所占角度
     */
    private float[] getAngles() {

        if (mValues == null || mValues.length == 0) return  null;
        double sum = 0;
        int len = mTitles.length;
        float[] angles = new float[len];

        for (int i = 0; i < len; i++) {
            sum += mValues[i];
        }
        float angle = 0;
        pieAngle = 360;
        /**-----把每个值所占的角度赋值给角度的数组,最后返回数组--------*/
        for (int i = 0; i < len - 1; i++) {
            angles[i] = (float) (pieAngle*mValues[i]/sum);
            angle += angles[i];
        }
        if (mValues[len-1]>0)
            angles[len-1] = pieAngle - angle;
        return angles;
    }

    private int getMaxTextWidth(double[] ds,float size) {
        String[] strs = new String[ds.length];
        for (int i = 0; i < ds.length; i++) {
            strs[i] = ds[i]+"";
        }
        return getMaxTextWidth(strs,size);
    }

    private int getMaxTextWidth(String[] strs,float size) {
        Rect textBound = new Rect();
        Paint paint = new Paint();
        paint.setTextSize(size);
        int len = 0;
        for (int i = 0; i < strs.length; i++) {
            paint.getTextBounds(strs[i],0,strs[i].length(),textBound);
            len = Math.max(len,textBound.width());
        }
        return len;
    }

    /**
     * 获取每块饼图所占的百分比
     * @param canvas
     */
    private String[] percents = new String[4];
    private void setPieContentText() {
        float pre = 0;
        float[] centerAngle = new float[mAngles.length];
        for (int i = 0; i < mAngles.length; i++) {
            if (mAngles[i] == 0) continue;
            centerAngle[i] = mAngles[i]/2 +pre;
            pre += mAngles[i];
        }
        float lastPir = 1.0f;//为了使所有的%加起来等于1
        mTextPaint.setColor(0xFFFFFFFF);
        for (int i = 0; i < centerAngle.length; i++) {
            if (centerAngle[i] == 0) continue;
            double curPer = numDecimals(mAngles[i]/pieAngle);
            String perMsg = i == centerAngle.length-1?percentFormat(lastPir):percentFormat(curPer);
            percents[i]=perMsg;
            lastPir -= curPer;
        }
    }

    /**
     * 格式化为百分比格式
     * @param num
     * @return
     */
    private String percentFormat(double num){
        DecimalFormat df = new DecimalFormat("#0.00%");
        return df.format(num);
    }
    /**
     * 保留四位小数
     * @param num
     * @return
     */
    public static double numDecimals(double num){
        return ((int)(num*10000))*1.0d/10000;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值