欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android: 一次自绘控件的体验

程序员文章站 2022-05-28 19:40:40
...

一个盆友在 qq 上面给我一个截图,问我有没有见过这种效果。我一看,貌似不太难,虽然我并不熟悉自定义控件,但是网上的教程很多,于是决定实现一下。

android: 一次自绘控件的体验

这个就是给我的截图。不是很清晰,也不完整。但是重点突出出来了。

于是,我看了看 HenCoder 的教程1,决定实现一下。(当然,实现期间,也翻阅了一下其他人的博客)

我实现的效果如下:

android: 一次自绘控件的体验

大体实现贴一下:

@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        this.mWidth = w;
        this.mHeight = h;

        min = Math.min(mWidth, mHeight);
        tableList = DynamicData.getViewSource();
        paint = new Paint();
        LogUtils.w(tableList);

        oval = new RectF(0, 0, min, min);
        icon = new RectF();

        diffLeft = min / 10;
        diffRight = diffLeft;
    }

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

        iconLength = 1f * min / 17;
        int height = (int) (iconLength / 2);
        for (Table t : tableList) {
            float left = min + diffLeft;
            float right = left + iconLength;
            float top = 0;
            float bottom = top + iconLength;
            paint.setColor(t.color);
            icon.set(left, height + top, right, height + bottom);
            canvas.drawRect(icon, paint);

            paint.setTextSize(iconLength);
            paint.setColor(Color.BLACK);
            canvas.drawText(t.name + "\t" + (int) t.percent + "%",
                    right + diffRight, height + bottom, paint);
            height += iconLength * 3;
        }
    }

    private void drawLeft(Canvas canvas) {
        paint.setColor(Color.parseColor("#dbdbdb"));
        canvas.drawRect(oval, paint);
        int start = 180;
        for (Table t : tableList) {
            float angle = (float) t.percent / 100 * 360;
            paint.setColor(t.color);
            paint.setStrokeCap(Paint.Cap.ROUND);

            scaleOval(t.scale);
            canvas.drawArc(oval, start, angle,
                    true, paint);
            start += angle;
        }
        paint.setColor(Color.WHITE);
        canvas.drawCircle(1f * min / 2, 1f * min / 2, min * 1f / 12, paint);
        scaleOval(1); // 要加这一句,不然 onStop 后再进来就变小了
    }

    private void scaleOval(float scale) {
        oval.set(0, 0, min, min);
        float left = 1f * min * (1 - scale) / 2;
        float top = 1f * min * (1 - scale) / 2;
        float right = 1f * min * scale + left;
        float bottom = 1f * min * scale + top;
        oval.set(left, top, right, bottom);
    }

嗯,里面的逻辑不复杂,主要是对系统 api 的调用,然后计算一下,每次画的起始位置。

其实,这种东西,我之前看到也会害怕,但是,真的很一般,不难的。


不过,这里还是有需要优化的地方,比如最小尺寸,如果设置成 wrap_conent 怎么处理,等等。我这里的逻辑全部是 onDraw()需要的,其他的,我没有去实现。

如果想看完整源码:献丑了,戳我。。。