自定义View控件之特殊的饼形图(环形图)

自定义View控件之特殊的饼形图(环形图)
2015/07/27最近因为项目需要写一个环形图,可以表示所占比例也可以表示进度,于是自己画了一个,觉得蛮有意思的,分享出来给大家看看。




功能分析

1, 一共六个环形,每个颜色,弧度不同,

2, 在每个环形上,根据其环的弧度不同,在弧的中心点上,伸出线,在线上显示相应的数值

3, 在线的结尾处,显示一个圆角方形,内部是其百分比。



六个环形的画法

般在画环形时,我们都是采用画圈,然后设置其style为空心,给StrokeWidth一个值,用它来设置环的宽,可是这里有一个问题,在设置完宽之后,它的这个宽是在边为1的情况下,向内外扩展。说简单一点,就是如果我们要画一个半径为100的环,如果你把StrokeWidth设成20,你会发现,最后画出来的,是一个半径为110的环。在这种情况下,我们在画环上线的时候,算其长度会有麻烦。

  我采用了一个比较笨的方法,就是画一个实心圆,然后再画一个半径减去环宽的小圆,这样就达到了圆环的效果。这样还有一个好处是,中心的圆的颜色也可以自定义了。

  这里其实最麻烦的是算环形的半径,这里我一直也没有想好有什么太好的方法,我的方法比较笨,就是取控件的高度一半,然后再减去一个值,因为我认为,这个控件是一个宽大于高的控件,因为左右会有伸出的线吗,所以相当来说,高就是比较小的哪个值,所以还要减一个值,是因为要给线上的值,留一个空位出来,看一下效果图,就明白什么意思了。




环上的线

这里我采用了三角函数进行计算弧的中心点,然后根据它的不同位置进行画线,这里无非就是八种情况,向右上折,向右全直,向右下折,垂直向下然后右直,重直向下左直,向左上折,向左全直,向左下折。而直线的长度,我是根据线上的文字的长度来确定,然后左右各留出10的宽度.



在线尾处画圆角方形和百分比 在线尾处画圆角方形和百分比

这一步就比较简单了,采用drawRoundRect就可以很轻松的完成。



package com.example.cg.customcirclepre.custom;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import com.example.cg.customcirclepre.R;

import java.text.DecimalFormat;

/**
 * 自定义的一个特殊饼状图
 * 作者:David Wang
 * 时间:2017/7/1 0006 上午 10:38
 */
public class MyCustomCirpre extends View {

    private float iBNum = 150;                                     //流入大单数
    private int iBColor = Color.parseColor("#EE755C");             //流入大单颜色
    private float iMNum = 200;                                     //流入中单数
    private int iMColor = Color.parseColor("#D7583E");             //流入中单颜色
    private float iSNum = 180;                                     //流入小单数
    private int iSColor = Color.parseColor("#C73F23");             //流入小单颜色
    private float oBNum = 660;                                     //流出大单数
    private int oBColor = Color.parseColor("#25D98E");             //流出大单颜色
    private float oMNum = 210;                                     //流出中单数
    private int oMColor = Color.parseColor("#2EBA80");             //流出中单颜色
    private float oSNum = 195;                                     //流出小单数
    private int oSColor = Color.parseColor("#1D8057");             //流出小单颜色

    private int StrokeWidth =  120;                                //弧的宽度
    private int TextSize = 30;                                     //文字大小


    private Paint mPaint;
    private RectF mRectf;
    private Rect mBound;

    private String txtNumPre;
    float[] point;                                                  //记录弧度最外边中心点的坐标

    private int adjustDist = 10;                                    //在弧度上面的线,为了调整其最好的显示位置设置一个调整的距离数

    private float txtBeginX = 0;                                    //线上文字开始的位置的X坐标值
    private float txtBeginY = 0;                                    //线上文字开始的位置的y坐标值
    private float txtEndX =0;                                       //线上文字结束的位置的x坐标值


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

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

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

        TypedArray array = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.MyPre, defStyleAttr, 0);
        int n = array.getIndexCount();
        for(int i=0;i<n;i++)
        {
            int arr = array.getIndex(i);
            switch (arr)
            {
                case R.styleable.MyPre_iBNum:
                    iBNum = array.getFloat(arr,0);
                    break;
                case R.styleable.MyPre_iBColor:
                    iBColor = array.getColor(arr,Color.parseColor("#EE755C"));
                    break;
                case R.styleable.MyPre_iMNum:
                    iMNum = array.getFloat(arr,0);
                    break;
                case R.styleable.MyPre_iMColor:
                    iMColor = array.getColor(arr,Color.parseColor("#D7583E"));
                    break;
                case R.styleable.MyPre_iSNum:
                    iSNum = array.getFloat(arr,0);
                    break;
                case R.styleable.MyPre_iSColor:
                    iSColor = array.getColor(arr,Color.parseColor("#C73F23"));
                    break;
                case R.styleable.MyPre_oBNum:
                    oBNum = array.getFloat(arr,0);
                    break;
                case R.styleable.MyPre_oBColor:
                    oBColor = array.getColor(arr,Color.parseColor("#25D98E"));
                    break;
                case R.styleable.MyPre_oMNum:
                    oMNum = array.getFloat(arr,0);
                    break;
                case R.styleable.MyPre_oMColor:
                    oMColor = array.getColor(arr,Color.parseColor("#2EBA80"));
                    break;
                case R.styleable.MyPre_oSNum:
                    oSNum = array.getFloat(arr,0);
                    break;
                case R.styleable.MyPre_oSColor:
                    oSColor = array.getColor(arr,Color.parseColor("#1D8057"));
                    break;
                case R.styleable.MyPre_StrokeWidth:
                    StrokeWidth = array.getInt(arr,200);
                    break;
                case R.styleable.MyPre_textSize:
                    TextSize = array.getDimensionPixelSize(arr, (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_SP, 12, getResources().getDisplayMetrics()));
                    break;
            }
        }

        array.recycle();


        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(5);
        mPaint.setStyle(Paint.Style.FILL);

        mRectf = new RectF();

        mBound = new Rect();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width ;
        int height ;

        if(widthMode==MeasureSpec.EXACTLY)
        {
            width = widthSize;
        }else
        {
            width = getPaddingLeft() + getWidth() + getPaddingRight();
        }

        if(heightMode==MeasureSpec.EXACTLY)
        {
            height = heightSize;
        }else
        {
            height = getPaddingTop() + getHeight() + getPaddingBottom();
        }

        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);


        float radius;        //定义半径
        float left;
        float top;
        float right;
        float bottom;


        radius = getHeight()/2 - 80;

        left = getWidth()/2 - radius  ;
        top = getHeight()/2 -radius  ;
        right = getWidth()/2 + radius;
        bottom = getHeight()/2 +  radius;

        mRectf.set(left, top, right, bottom);


        //计算总数
        float sum = oBNum + oMNum + oSNum + iBNum + iMNum + iSNum;

        //计算六个值的百分比
        float oBpre = oBNum / sum;
        float oMpre = oMNum / sum;
        float oSpre = oSNum / sum;
        float iBpre = iBNum / sum;
        float iMpre = iMNum / sum;
        float iSpre = iSNum / sum;

        //计算六个值所占圆的弧度数
        float oBArc = oBpre * 360;
        float oMArc = oMpre * 360;
        float oSArc = oSpre * 360;
        float iBArc = iBpre * 360;
        float iMArc = iMpre * 360;
        float iSArc = iSpre * 360;


        /**
         * 画出六个扇面
         */
        mPaint.setColor(oBColor);
        canvas.drawArc(mRectf, 270, oBArc, true, mPaint);

        mPaint.setColor(oMColor);
        canvas.drawArc(mRectf, 270 + oBArc, oMArc, true, mPaint);

        mPaint.setColor(oSColor);
        canvas.drawArc(mRectf, 270 + oBArc + oMArc, oSArc, true, mPaint);

        mPaint.setColor(iSColor);
        canvas.drawArc(mRectf, 270 + oBArc + oMArc + oSArc, iSArc, true, mPaint);

        mPaint.setColor(iMColor);
        canvas.drawArc(mRectf, 270 + oBArc + oMArc + oSArc + iSArc, iMArc, true, mPaint);

        mPaint.setColor(iBColor);
        canvas.drawArc(mRectf, 270 + oBArc + oMArc + oSArc + iSArc + iMArc, iBArc, true, mPaint);

        /**
         * 画出中间的空白区域
         */
        mPaint.setColor(Color.parseColor("#ffffff"));
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius - StrokeWidth, mPaint);


//        DrawOB(canvas, radius, oBArc, oBpre);
//
//        DrawOM(canvas, radius, oBArc, oMArc, oMpre);
//
//        DrawOS(canvas, radius, oBArc + oMArc, oSArc, oSpre);
//
//        DrawIS(canvas, radius, oBArc + oMArc + oSArc, iSArc, iSpre);
//
//        DrawIM(canvas, radius, oBArc + oMArc + oSArc + iSArc, iMArc, iMpre);
//
//        DrawIB(canvas,radius,oBArc + oMArc + oSArc + iSArc + iMArc,0,0);
    }











    /**
     * 格式化显示的百分比
     * @param proValue   传入的数值一般是0.1234这种格式的
     * @return           返回一个小数点后一位的百分比字符串
     */
    private String getProValText(float proValue)
    {
        DecimalFormat format = new DecimalFormat("#0.0");
        return format.format(proValue * 100) + "%";
    }


    public void setNum(float oBNum,float oMNum, float oSNum,float iBNum,float iMNum,float iSNum)
    {
        this.oBNum = oBNum;
        this.oMNum = oMNum;
        this.oSNum = oSNum;
        this.iBNum = iBNum;
        this.iMNum = iMNum;
        this.iSNum = iSNum;

        postInvalidate();
    }
}


源代码:AnnulusCirclePre.zip


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值