Android使用cavans绘制饼图

项目中需要实现一个一级佣金以及二级佣金的比例示意图。看下设计稿
这里写图片描述

一、分析

一开始分析的是,先绘制完圆环,然后再去找到各自圆环的中心点,进行做切线,做中垂线出来绘制折线,然后绘制佣金比例以及显示。后面发现这么计算太麻烦了。索性就定死那个两个折线图以及比例显示。大概的思路如下图。会进行一系列简化。

这里写图片描述

1、简化点,把折线显示部分设置成了固定,然后圆环在动。
2、因为我们使用canvas绘制圆环或者圆的时候,其实是在一个矩形区域中绘制的,所以我们简化了折线那一部分,就是圆距离矩形左下(右上)角的距离,然后水平方向就是raduis的长度,半径长度。
3、可以看到设计稿纸上我们有一个圆弧之间的一个间距,与底色相同颜色为了区分两个圆环。这里可以采用绘制完圆环后在上层重新绘制那调白线,那就需要计算各点坐标绘制两条折线,我后面一想,还可以采用在同一个rectf区域中覆盖一个相同半径的空心圆环,ok,顿时没有了难点有木有。实心嵌套空心圆环实现两个圆环之间的

4、看下我实现的最终效果图

这里写图片描述

二、计算各点坐标
注意,我们的坐标是重左上角开始的。。。往下或者往右走
这里再继续解释下,绘制圆弧的角度问题吧(顺时针旋转)如下图

这里写图片描述

看下绘制圆弧需要传入的参数 
drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
            @NonNull Paint paint)
oval圆弧切过的矩形区域
startAngle开始角度
sweepAngle扫过的角度(需要绘制的角度)
useCenter是否要连着圆心绘制
paint画笔
圆心坐标(2mRaduis,2mRaduis)
矩形区域RectF坐标(mRaduis, mRaduis, mRaduis * 3, mRaduis * 3)
左下角圆弧起始角度,扫过角度(第一佣金比例)
startAngle=135 - (mFirstPoint / 100 * 360) / 2
sweepAngle=(mFirstPoint / 100 * 360)

右上角圆弧起始角度,扫过角度(第二佣金比例)

startAngle=315 - (360 - mFirstPoint / 100 * 360) / 2
sweepAngle=(360 - mFirstPoint / 100 * 360)

左下角折线

 canvas.drawLine((float) (1 - Math.sqrt(2) / 2) * mRaduis + mRaduis, (float) (1 + Math.sqrt(2) / 2) * mRaduis + mRaduis, mRaduis, 3 * mRaduis, mTextPaint);
canvas.drawLine(mRaduis, 2 * mRaduis + mRaduis, 0, 3 * mRaduis, mTextPaint);

右下角折线
 canvas.drawLine((float) (2 + Math.sqrt(2) / 2) * mRaduis, (float) (2 * mRaduis - Math.sqrt(2) / 2 * mRaduis), 3 * mRaduis, mRaduis, mTextPaint);
 canvas.drawLine(3 * mRaduis, mRaduis, 4 * mRaduis, mRaduis, mTextPaint);

三、实现功能代码

1、attr文件中的自定义属性

 <!--圆环饼图-->
    <declare-styleable name="CircleChart">
        <attr name="mRaduis" format="dimension" />
        <attr name="mFirstPoint" format="float" />
        <attr name="mLinewith" format="dimension" />
        <attr name="mLineColor" format="color" />
        <attr name="mFirstPointColor" format="color" />
        <attr name="mSecondPointColor" format="color" />
        <attr name="mPointTextsize" format="dimension" />
        <attr name="mStokeColor" format="color" />
        <attr name="mTextColor" format="color" />
    </declare-styleable>

2、自定义饼图控件:CircleChart.java

package com.xx.xx.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;

import com.coofond.carservices.R;

/**
 * @description: 我的分享饼图
 * @Author zsj on 2017/2/21 15:24.
 */

public class CircleChart extends TextView {
    /**
     * 饼图半径
     */
    private int mRaduis;
    /**
     * 一级佣金颜色
     */
    private int mFirstPointColor;
    /**
     * 二级佣金颜色
     */
    private int mSecondPointColor;

    /**
     * 第一佣金比例
     */
    private float mFirstPoint;
    /**
     * 饼图上的字体大小
     */
    private int mPointTextSize;
    /**
     * 线条宽度
     */
    private int mLineWith;
    /**
     * 线条颜色
     */
    private int mLineColor;
    /**
     * 填充的画笔
     */
    private Paint mPaint;

    /**
     * 用来描边的画笔
     */
    private Paint mStokePaint;
    /**
     * 描边颜色
     */
    private int mStokeColor;
    /**
     * 绘制文字的画笔
     */
    private Paint mTextPaint;
    /**
     * 绘制文字的颜色
     */
    private int mTextColor;

    /**
     * @param mFirstPoint 设置第一佣金比例
     */
    public void setmFirstPoint(float mFirstPoint) {
        this.mFirstPoint = mFirstPoint;
    }



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

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

    public CircleChart(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        /**
         * 获取我们的自定义属性
         */
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CircleChart, defStyleAttr, 0);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case R.styleable.CircleChart_mRaduis:
                    mRaduis = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.CircleChart_mFirstPoint:
                    mFirstPoint = a.getFloat(attr, 50);
                    break;
                case R.styleable.CircleChart_mLinewith:
                    mLineWith = a.getDimensionPixelOffset(attr, (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.CircleChart_mLineColor:
                    mLineColor = a.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.CircleChart_mFirstPointColor:
                    mFirstPointColor = a.getColor(attr, Color.BLUE);
                    break;
                case R.styleable.CircleChart_mSecondPointColor:
                    mSecondPointColor = a.getColor(attr, Color.RED);
                    break;
                case R.styleable.CircleChart_mPointTextsize:
                    mPointTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_SP, 12, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.CircleChart_mStokeColor:
                    mStokeColor = a.getColor(attr, Color.WHITE);
                    break;
                case R.styleable.CircleChart_mTextColor:
                    mTextColor = a.getColor(attr, Color.BLACK);
                    break;
            }
        }
        a.recycle();
        //初始化paint
        mPaint = new Paint();
        mStokePaint = new Paint();
        mTextPaint = new Paint();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        mPaint.setAntiAlias(true);//消除锯齿
        mStokePaint.setAntiAlias(true);//消除锯齿
        mTextPaint.setAntiAlias(true);//消除锯齿
        mStokePaint.setStyle(Paint.Style.STROKE);
        mStokePaint.setStrokeWidth(mLineWith / 2);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(mFirstPointColor);
        mStokePaint.setColor(mStokeColor);
        RectF oval = new RectF(mRaduis, mRaduis, mRaduis * 3, mRaduis * 3);
        //绘制实心圆弧
        canvas.drawArc(oval, 135 - (mFirstPoint / 100 * 360) / 2, (mFirstPoint / 100 * 360), true, mPaint);
        //绘制与底色相同的圆环
        canvas.drawArc(oval, 135 - (mFirstPoint / 100 * 360) / 2, (mFirstPoint / 100 * 360), true, mStokePaint);
        mPaint.setColor(mSecondPointColor);
        //绘制实心圆弧
        canvas.drawArc(oval, 315 - (360 - mFirstPoint / 100 * 360) / 2, (360 - mFirstPoint / 100 * 360), true, mPaint);
        //绘制与底色相同的圆环
        canvas.drawArc(oval, 315 - (360 - mFirstPoint / 100 * 360) / 2, (360 - mFirstPoint / 100 * 360), true, mStokePaint);
        mTextPaint.setColor(mTextColor);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setStrokeWidth(1);
        //绘制折线
        canvas.drawLine((float) (1 - Math.sqrt(2) / 2) * mRaduis + mRaduis, (float) (1 + Math.sqrt(2) / 2) * mRaduis + mRaduis, mRaduis, 3 * mRaduis, mTextPaint);
        canvas.drawLine(mRaduis, 2 * mRaduis + mRaduis, 0, 3 * mRaduis, mTextPaint);
        canvas.drawLine((float) (2 + Math.sqrt(2) / 2) * mRaduis, (float) (2 * mRaduis - Math.sqrt(2) / 2 * mRaduis), 3 * mRaduis, mRaduis, mTextPaint);
        canvas.drawLine(3 * mRaduis, mRaduis, 4 * mRaduis, mRaduis, mTextPaint);
        //绘制文字
        mTextPaint.setColor(mTextColor);
        mTextPaint.setTextSize(mPointTextSize);
        canvas.drawText("一级佣金", 0, 3 * mRaduis - mRaduis / 20, mTextPaint);
        canvas.drawText("二级佣金", 4 * mRaduis - mTextPaint.measureText("二级佣金"), mRaduis - mRaduis / 20, mTextPaint);
        mTextPaint.setColor(mFirstPointColor);
        canvas.drawText((int) mFirstPoint + "%", 0, 3 * mRaduis + mRaduis / 20 + mPointTextSize, mTextPaint);
        mTextPaint.setColor(mSecondPointColor);
        canvas.drawText((int) (100 - mFirstPoint) + "%", 4 * mRaduis - mTextPaint.measureText("75%"), mRaduis + mRaduis / 20 + mPointTextSize, mTextPaint);
    }

}

3、xml文件引用

 <com.xx.xx.widget.CircleChart
        android:id="@+id/cir_point"
        android:layout_width="240dp"
        android:layout_height="200dp"
        android:layout_gravity="center"
        android:layout_marginBottom="20px"
        android:layout_marginTop="-80px"
        app:mFirstPoint="10"
        app:mFirstPointColor="@color/textorange"
        app:mLinewith="5dp"
        app:mPointTextsize="14sp"
        app:mRaduis="60dp"
        app:mSecondPointColor="@color/orange"
        app:mStokeColor="@color/activitycolor"
        app:mTextColor="@color/textcolordark" />

4、activity中调用

cirPoint.setmFirstPoint(60);//获取这个控件直接set...就这么简单

源代码:https://github.com/TrebleZ/circletest

CSDN下载地址:http://download.csdn.net/detail/z_zt_t/9766113

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值