自定义View之饼状图

一、前言

上一篇介绍上自定义View之柱状图,本篇介绍自定义饼状图,主要也是因为项目中的的需要,有个不同比例的数组或列表展示,并且第一次初始化时有个动画效果,即根据当前进度绘制数组或列表中的数据。话不多说,先上效果图:


二、实现步骤

1.定义PieChartView继承View,给PieChartView添加自定义属性:

即在value目录下找到attrs.xml文件,在文件中可以定义PieChartView用到的属性,比如颜色、字体大小等属性。文件内容如下:

<declare-styleable name="PieChartView">
        <attr name="arcWidth" format="dimension"/><!-- 饼状图圆环宽度 -->
        <attr name="arcOrginColor" format="color"/><!-- 圆环初始颜色 -->
        <attr name="arcCoverColor" format="color"/><!-- 圆环覆盖颜色 -->
        <attr name="centerText" format="string"/><!-- 中间文字-->
        <attr name="centerTextSize" format="dimension"/><!-- 中间文字大小 -->
        <attr name="centerTextColor" format="color"/><!-- 中间文字颜色 -->
    </declare-styleable>

2.在.xml布局文件中对自定义的属性进行设置:

<com.cyj.piechartview.PieChartView
        android:id="@+id/pie_chart_view"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_marginTop="20dp"
        android:layout_centerHorizontal="true"
        app:arcWidth="30dp"
        app:centerText="分布情况"
        app:centerTextColor="@color/mainColor"
        app:centerTextSize="18sp"
        app:arcOrginColor="@color/subColor5"
        app:arcCoverColor="@color/accentColor"/>




3.PieChartView的构造方法中获得自定义的属性,主要代码如下:

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

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PieChartView);
        arcWidth = typedArray.getDimension(R.styleable.PieChartView_arcWidth, 20);
        arcOrginColor = typedArray.getColor(R.styleable.PieChartView_arcOrginColor, getResources().getColor(R.color.color_gray));
        arcCoverColor = typedArray.getColor(R.styleable.PieChartView_arcCoverColor, getResources().getColor(R.color.accentColor));
        centerTextSize = typedArray.getDimension(R.styleable.PieChartView_centerTextSize, 18);
        centerText = typedArray.getString(R.styleable.PieChartView_centerText);
        centerTextColor = typedArray.getColor(R.styleable.PieChartView_centerTextColor, getResources().getColor(R.color.mainColor));
        typedArray.recycle();

        init();
    }
4.初始化画笔及一些必要变量,代码如下:

private void init() {
        arcPaint.reset();
        arcPaint.setAntiAlias(true);//用来防止边缘的锯齿
        arcPaint.setStrokeWidth(arcWidth);
        arcPaint.setStyle(Paint.Style.STROKE); //画笔类型 STROKE空心 FILL 实心
        arcPaint.setColor(arcOrginColor);

        arcCoverPaint.reset();
        arcCoverPaint.setAntiAlias(true);//用来防止边缘的锯齿
        arcCoverPaint.setStrokeWidth(arcWidth);
        arcCoverPaint.setStyle(Paint.Style.STROKE); //画笔类型 STROKE空心 FILL 实心
        arcCoverPaint.setColor(arcOrginColor);

        mCenterTextPaint = new Paint();
        mCenterTextPaint.setStyle(Paint.Style.FILL);
        mCenterTextPaint.setColor(centerTextColor);
        mCenterTextPaint.setTextSize(centerTextSize);
        mCenterTextPaint.setAntiAlias(true);
    }

5.重写onMeasure()方法。在onMeasure()方法中完成当布局为wrap_content时设置默认长宽。代码如下:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        setMeasuredDimension(measure(widthMeasureSpec), measure(heightMeasureSpec));
    }

    private int measure(int origin) {

        int result = DEFAULT_MIN_WIDTH;
        int specMode = MeasureSpec.getMode(origin);
        int specSize = MeasureSpec.getSize(origin);

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

    }

6.重写onDraw方法。在onDraw方法中完成饼状图的绘制。代码如下

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        width = getWidth();
        height = getHeight();
        center = width > height ? height / 2 : width / 2;

        radius = (int) (center - arcWidth / 2); // 圆环的半径

        rectF = new RectF(center - radius, center - radius, center + radius, center + radius);


        drawOrginArc(canvas);//画初始圆环

        drawCoverArc(canvas);//画彩色圆环

        drawCenterText(canvas);//画中间值


    }

主要完全以下几个部分的绘制:

a.绘制初始圆环,代码如下:

private void drawOrginArc(Canvas canvas) {
        arcPaint.setColor(arcOrginColor);
        canvas.drawArc(rectF, 0, 360, false, arcPaint);
    }

b.绘制彩色圆环根据动画进度绘制,为了实现动画效果,绘制过程中有个计算当前绘制角度,具体看代码中注释,代码如下:

private void drawCoverArc(Canvas canvas) {

        float mStartAngle = 0;
//        for (int i = 0; i < value.length; i++) {
//            arcCoverPaint.setColor(valueColors[i]);
//            float angle = 360 * value[i];
//            canvas.drawArc(rectF, mStartAngle, angle, false, arcCoverPaint);
//            mStartAngle += angle;
//        }

        int poisition = 0;
        float currentVauleSum = 0;

        //该for循环判断当前currentValue处于列表或数组第几个位置
        for (int i = 0; i < value.length; i++) {
            currentVauleSum = 0;
            for (int j = 0; j <= i; j++) {// 前i个的和
                currentVauleSum += value[j];
                currentVauleSum = (float) (Math.round(currentVauleSum * 100)) / 100;
            }

            float currentRate = currentValue / 360;
            if (currentRate <= currentVauleSum) {
                poisition = i;
                break;
            }

        }
        //根据currentValue所处于列表或数组的位置 分别进行绘制
        for (int i = 0; i <= poisition; i++) {
            if (i == poisition) {//根据当前currentValue值绘制圆环
                arcCoverPaint.setColor(valueColors[i]);
                canvas.drawArc(rectF, mStartAngle, currentValue - mStartAngle, false, arcCoverPaint);

            } else {// i<poisition 绘制当前i的完整圆环
                arcCoverPaint.setColor(valueColors[i]);
                float angle = 360 * value[i];
                canvas.drawArc(rectF, mStartAngle, angle, false, arcCoverPaint);
                mStartAngle += angle;
            }

        }

    }

通过如下方法改变currentValue值:

//初始化动画加载进度
        valueAnimator = ValueAnimator.ofFloat(0, 360);
        valueAnimator.setDuration(2000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                currentValue = (Float) valueAnimator.getAnimatedValue();
                invalidate();       //动画效果
            }
        });


 3.绘制饼状图中间的文字

private void drawCenterText(Canvas canvas) {
        //画中间数值
        float baseLine = center - (mCenterTextPaint.getFontMetrics().descent + mCenterTextPaint.getFontMetrics().ascent) / 2;
        mCenterTextPaint.setTextAlign(Paint.Align.CENTER);
        canvas.drawText(centerText, center, baseLine, mCenterTextPaint);
    }


三、使用

在Activity中初始化饼状图数据数组或列表,并开启动画效果:

float[] value = {0.1f, 0.4f, 0.2f, 0.3f};
        pie_chart_view.initAndStart(value);


上面已经贴出了实现的关键代码,完整demo可以参考:https://github.com/yjchen920927/PieChartView


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值