android 自定义view 画饼图

android 自定义view 画饼图

实现难点
通过canvas.drawArc()来画出扇形,关键在于角度的计算和计算表述线的位置。具体的实现逻辑看下面的分解
实现逻辑
  • 得到之前扇形的角度和
 for (int j = 0; j < i; j++) {
                //计算之前的角度之和
                degree += mBeanList.get(j).getF();
            }
  • 计算当前对象的角度
int arcDegree = (int) (mBeanList.get(i).getF() * 360);
  • 画出扇形
canvas.drawArc(xWidth - radius, yHeight - radius, xWidth + radius, yHeight + radius, (float) (degree * 360), arcDegree, true, mPaint);
  • 画表述的线,先计算表述的线的起点相对于0°的角度
 //得出画表述那条线的相对于起点的角度---->    degree * 360 表示之前所有的对象的角度和,  arcDegree / 2表示自己的角度的一半
int lineDegree = (int) (degree * 360 + (arcDegree / 2));
  • 算出表述线相对于半径的x和y的坐标
  float x = (float) (radius * Math.cos(Math.toRadians(lineDegree)));
  float y = (float) (radius * Math.sin(Math.toRadians(lineDegree)));
  • 移动到当前点,然后画线,其中xM表示短的表述线x轴的长度,xxM表示长的表述线x轴的长度,yM表示长的表述线的y轴的长度,通过对角度的判断,选择表述线的方向。
mPath.moveTo(xWidth + x, yHeight + y);
            //短横线的距离
            int xM = 30;
            //长横线的距离
            int xxM = 110;
            //长横线y轴距离
            int yM = 80;
            //表述的线沿着空白处伸展
            if (lineDegree > 90 && lineDegree < 180) {
                xM = -xM;
                xxM = -xxM;
            } else if (lineDegree >= 180 && lineDegree <= 270) {
                xM = -xM;
                xxM = -xxM;
                yM = -yM;
            }
            mPath.lineTo(xWidth + x + xM, yHeight + y);
            mPath.lineTo(xWidth + x + xxM, yHeight + y + yM);
            mPaint.setColor(Color.BLACK);
            canvas.drawPath(mPath, mPaint);
  • 画出表述文字
canvas.drawText(mBeanList.get(i).getName(), xWidth + x + xxM, yHeight + y + yM, mPaint);
  • 最后需要注意的是将 path reset
mPath.reset();
View源码
public class XunView extends View {

    List<Bean> mBeanList;
    Paint mPaint;
    Path mPath;
    int width;
    int height;
    int radius;

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

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

    public XunView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mBeanList = new ArrayList<>();
        mPaint = new Paint();
        mPath = new Path();
        radius = 200;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        this.width = getWidth();
        this.height = getHeight();
    }

    public List<Bean> getBeanList() {
        return mBeanList;
    }

    public void setBeanList(List<Bean> beanList) {
        mBeanList = beanList;
        this.invalidate();
    }

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int xWidth = width / 2;
        int yHeight = height / 2;

        for (int i = 0; i < mBeanList.size(); i++) {
            mPaint.setColor(mBeanList.get(i).getColor());
            mPaint.setTextAlign(Paint.Align.CENTER);
            mPaint.setTextSize(30);
            //设置画线的宽度
            mPaint.setStrokeWidth(5);
            double degree = 0;
            for (int j = 0; j < i; j++) {
                //计算之前的角度之和
                degree += mBeanList.get(j).getF();
            }
            //计算当前对象的角度
            int arcDegree = (int) (mBeanList.get(i).getF() * 360);
            canvas.drawArc(xWidth - radius, yHeight - radius, xWidth + radius, yHeight + radius, (float) (degree * 360), arcDegree, true, mPaint);
            //得出画表述那条线的相对于起点的角度---->    degree * 360 表示之前所有的对象的角度和,  arcDegree / 2表示自己的角度的一半
            int lineDegree = (int) (degree * 360 + (arcDegree / 2));
            float x = (float) (radius * Math.cos(Math.toRadians(lineDegree)));
            float y = (float) (radius * Math.sin(Math.toRadians(lineDegree)));
            mPaint.setStyle(Paint.Style.STROKE);
            mPath.moveTo(xWidth + x, yHeight + y);
            //短横线的距离
            int xM = 30;
            //长横线的距离
            int xxM = 110;
            //长横线y轴距离
            int yM = 80;
            //表述的线沿着空白处伸展
            if (lineDegree > 90 && lineDegree < 180) {
                xM = -xM;
                xxM = -xxM;
            } else if (lineDegree >= 180 && lineDegree <= 270) {
                xM = -xM;
                xxM = -xxM;
                yM = -yM;
            }
            mPath.lineTo(xWidth + x + xM, yHeight + y);
            mPath.lineTo(xWidth + x + xxM, yHeight + y + yM);
            mPaint.setColor(Color.BLACK);
            canvas.drawPath(mPath, mPaint);

            canvas.drawText(mBeanList.get(i).getName(), xWidth + x + xxM, yHeight + y + yM, mPaint);

            mPaint.setStyle(Paint.Style.FILL);
            mPath.reset();
        }
    }
}
bean实体
public class Bean {
    private double f; // 比例
    private int mColor;
    private String name;



    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getF() {
        return f;
    }

    public void setF(double f) {
        this.f = f;
    }

    public int getColor() {
        return mColor;
    }

    public void setColor(int color) {
        mColor = color;
    }
}
Activity中的调用
public class MainActivity extends AppCompatActivity {
    XunView mXunView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mXunView = (XunView) findViewById(R.id.bing_view);
        ArrayList<Bean> list = new ArrayList<>();
        Bean bean = new Bean();
        bean.setColor(Color.argb(255, 255, 154, 50));
        bean.setF(0.2);
        bean.setName("JAVA");

        Bean bean1 = new Bean();
        bean1.setColor(Color.argb(255, 101, 50, 151));
        bean1.setF(0.2);
        bean1.setName("GB");

        Bean bean2 = new Bean();
        bean2.setColor(Color.argb(255, 0, 153, 49));
        bean2.setF(0.2);
        bean2.setName("C++");

        Bean bean3 = new Bean();
        bean3.setColor(Color.argb(255, 0, 204, 253));
        bean3.setF(0.3);
        bean3.setName("C#");

        Bean bean4 = new Bean();
        bean4.setColor(Color.argb(255, 254, 0, 0));
        bean4.setF(0.1);
        bean4.setName("VB");

        list.add(bean);
        list.add(bean1);
        list.add(bean2);
        list.add(bean3);
        list.add(bean4);
        mXunView.setBeanList(list);
    }
}
xml中的编写
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.moneyview.MainActivity"
    >

    <com.example.moneyview.XunView
        android:id="@+id/bing_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

效果图

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值