动手实现饼图控件

一直以来,对自定义控件处于模模糊糊的状态,不知道怎样去入手实现一个控件出来.前段时间leader带我们梳理了相关知识点,并且自己又巩固了一下相关的内容.俗话说还记性不如烂笔头,不动手去实践,一边学习一边也就把之前的忘得差不多了.这两天终于下定决心真正动手尝试一下,实现一个真正的属于自己的自定义控件.好了扯远了,先上效果看一下效果.

        ps:第一次发帖,也是刚刚学会自定义view这一部分,大神请绕行,勿喷轻喷,多谢!


        便于看view的整体位置,对其加了一个背景颜色.

        开始肯定要做一些初始化的工作,初始化画笔,设置画笔的颜色啦,抗锯齿等等,这里直接给出代码:

// 画饼图的画笔
anglePaint = new Paint();
// 抗锯齿
anglePaint.setAntiAlias(true);
// 画文字的画笔
mTextPaint = new Paint();
// 设置画笔颜色
mTextPaint.setColor(Color.WHITE);
// 设置字体大小
mTextPaint.setTextSize(34);
// 以文本内容的中心点为基准
mTextPaint.setTextAlign(Paint.Align.CENTER);
// 抗锯齿
mTextPaint.setAntiAlias(true);

        细心的小伙伴们可能会发现,画饼图的画笔在这里没有设置颜色,原因是它需要根据不同的颜色去不断更改对其的更改.做这个的时候出于从现实开发角度着想,对外提供了设置数据的方法,可以将真实的后台数据(角度或者占比,颜色等)通过对外提供的方法设置进来.相对应的伪代码:

public class MainActivity extends AppCompatActivity {

    private ArrayList<PieBean> mList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        CustomPieView customPieView = findViewById(R.id.my_custom_pie_view);
        initData();
        // 将数据设置给控件
        customPieView.setDate(mList);
    }

    /**
     * 模拟数据
     */
    private void initData() {
        mList = new ArrayList<PieBean>();

        PieBean pieBean1 = new PieBean();
        pieBean1.angle = 160;
        pieBean1.color = "#FF0000";
        pieBean1.content = "红色";
        mList.add(pieBean1);

        PieBean pieBean2 = new PieBean();
        pieBean2.angle = 60;
        pieBean2.color = "#0000FF";
        pieBean2.content = "蓝色";
        mList.add(pieBean2);

        PieBean pieBean3 = new PieBean();
        pieBean3.angle = 70;
        pieBean3.color = "#CCCCCC";
        pieBean3.content = "灰色";
        mList.add(pieBean3);

        PieBean pieBean4 = new PieBean();
        pieBean4.angle = 50;
        pieBean4.color = "#7FFF00";
        pieBean4.content = "绿色";
        mList.add(pieBean4);

        PieBean pieBean5 = new PieBean();
        pieBean5.angle = 20;
        pieBean5.color = "#FFFF00";
        pieBean5.content = "黄色";
        mList.add(pieBean5);
    }
}

        给个对象有它自己的:角度(也可以改为占比)、颜色、和要显示的文本.接下来就是画了:

        先贴出代码,然后我们一步步讲解.

@Override
protected void onDraw(Canvas canvas) {

    // 创建矩形模型,在其内部进行绘制
    RectF rectF = new RectF(0, 0, getWidth(), getHeight());

    // 累计每次的角度合
    int drawSectorTotalAngle = -45;
    // 画扇形
    for (int i = 0; i < mList.size(); i++) {
        anglePaint.setColor(Color.parseColor(mList.get(i).color));
        canvas.drawArc(rectF, drawSectorTotalAngle, mList.get(i).angle, true, anglePaint);
        drawSectorTotalAngle += mList.get(i).angle;
    }

    /**
     * 坐标公式:
     * x = 原点 + r * cos(angle * π / 180)
     * y = 原点 + r * sin(angle * π /180)
     */
    // 累计每次的角度合
    int drawTextTotleAngle = -45;
    // 画文本
    for (int i = 0; i < mList.size(); i++) {
        float x = (float) (getWidth() / 2 + getWidth() / 2.5 * (Math.cos((mList.get(i).angle / 2 + drawTextTotleAngle) * 3.14 / 180)));
        float y = (float) (getHeight() / 2 + getWidth() / 2.5 * (Math.sin((mList.get(i).angle / 2 + drawTextTotleAngle) * 3.14 / 180)));
        canvas.drawText(mList.get(i).content, x, y, mTextPaint);
        drawTextTotleAngle += mList.get(i).angle;
    }

    super.onDraw(canvas);
}

        首先创建了一个矩形,用来在其内部绘制我们的图形.下面设置一个变量,是绘制的起始角度,默认从0开始,0的起始点绘制出来是x轴的0坐标逆时针方向绘制,此处我改为了负45度,起始没什么不一样的,就是从负45度开始绘制,相信大家都能明白.然后根据数据进行绘制,每次先给画笔进行了颜色的设置,然后用画布的drawArc绘制弧度.

        说一下drawArc方法参数,第一个参数就是我们上面指定的矩形区域,指定在哪个矩形区域进行绘制.第二个参数是起始坐标,起始坐标需要说明一下,每次绘制都需要一个起始坐标,而且每次绘制,是基于上一次绘制的结束位置开始绘制,如果不明白的话,请看这里(加入现在我们将圆圈等分为4份进行绘制,第一次的绘制角度是从0绘制到90度,那么第二次的起始角度,就是从90度开始绘制,绘制到180度,第三次呢就是从180度绘制到270,第四次从270度绘制到360度,这样绘制4次,就可以画出一个圆).我们用提前写好的变量记录每次绘制了多少角度,便于下次用来绘制起始角度.第三个参数就是绘制到多少角度.第四个参数是问绘制时是否需要穿过中心点.

        接着往下,又是一个for循环,可能有的小伙伴就要问了,""怎么你非要写2个for循环一个画弧一个画文本啊?一个不行吗?"简单说明一下,一个for当然可以,只是在一个循环中,画一个弧,再画一个文本,这样循环N次以后,运行起来会发现前面画的文本被后来画的弧遮挡了,想一想循环的逻辑不难理解.

        画文本的时候需要根据弧度去进行绘制,起码要在弧度以内进行绘制,所以这里又涉及到了数学的知识,本人对数学...不想多说,这里用到的根据弧度求坐标系的x与y点也是琢磨了好长时间..对于那些数学好的同学,估计又要被鄙视了...drawText方法的参数想必大家一目了然,还是简单说明一下,第一个参数就是要绘制的文本,第二和第三个参数对应的就是x和y轴坐标,第四个参数固然就是画笔了.

        好了,大功告成,运行——走你~看着自己完成的第一个自定义控件还真是有些激动.

        在这个自定义view中,并未涉及到onMesure,这里简单说一说这个方法.onMesure方法会接收到2个参数,根据它们,我们可以知道父控件对子控件的约束条件,说白了,就是父控件对子控件约束了最大可展示的空间.由于本篇是以getWidth(圆的直径)去绘制的,所以不管在布局中为控件设置了多大的控件一般都不会影响view的展示,除非父控件的大小指定的小于本控件的大小,那么此控件肯定是显示不全.如果在这种情况下,还想完全展示饼图的话,可以在获取到父控件的规则后,再按比例设置自己的宽高.

        说些题外话,其实实现一个东西的方法有很多,大胆去尝试一下,不动手去敲不实践一下,永远不知道自己其实也是蛮强的,之前我也是有些抵触自定义view这块的东西,总觉得模模糊糊知道吧又不知道,真的动手以后,觉得也没有想象中那么难,说了这么多,也当是给自己鼓气.

        本篇就写到这里,后续会不定期的更新这个控件的功能(必定还是要以开发任务为主),也会再去学习自己没有接触过的新知识,待理解掌握后,拿来巩固与分享.

        github地址:    https://github.com/zhangyue19890303/CustomPieView.git

猜你喜欢

转载自blog.csdn.net/nannan1989yue/article/details/80451319