android圆环带刻度进度条

目录表

这是最终的实现效果(左下),主要包括刻度线的实现、颜色渐变及外围的文字效果:

在这里插入图片描述

实现分析

此效果由view绘制实现,用到了圆形、过圆心弧及文字这几种基本图形的绘制api。刻度线的绘制则是通过不断旋转canvas画布来循环画线实现的,都是比较常规的绘制方案。

此view的难点是外围文字在环绕过程中,坐标位置的确认,即依圆心坐标,半径,扇形角度,如何计算出扇形终射线与圆弧交叉点的xy坐标,所幸网上都能找到解决方案及背后的数学模型。代码如下:

    // 绘制外围文字
    private void paintOutWord(Canvas canvas, String state) {
        PointF progressPoint = CommentUtil.calcArcEndPointXY
                (radius + getPaddingLeft() + specialScaleLineLength + scaleToRingSpace + wordWith
                        , radius + getPaddingTop() + specialScaleLineLength + scaleToRingSpace + wordHeigh
                        , radius + specialScaleLineLength + scaleToRingSpace
                        , progress * (360 / 100f), -90);
        int left = (int) progressPoint.x;
        int top = (int) progressPoint.y;
        wordPaint.getTextBounds(state, 0, state.length(), rect);
        if(left < radius + getPaddingLeft() + specialScaleLineLength + scaleToRingSpace + wordWith){
            left -= rect.width();
        }
        if(top > radius + getPaddingTop() + specialScaleLineLength + scaleToRingSpace + wordHeigh){
            top += rect.height();
        }
        canvas.drawText(state, left, top, wordPaint);
    }

此方法的作用即获取扇形终射线与圆弧交叉点的xy坐标,感兴趣的可以研究下:

    /**
     * 依圆心坐标,半径,扇形角度,计算出扇形终射线与圆弧交叉点的xy坐标
     * @param cirX 圆centerX
     * @param cirY 圆centerY
     * @param radius 圆半径
     * @param cirAngle 当前弧角度
     * @param orginAngle 起点弧角度
     * @return 扇形终射线与圆弧交叉点的xy坐标
     */
    public static PointF calcArcEndPointXY(float cirX, float cirY, float radius, float
            cirAngle, float orginAngle) {
        cirAngle = (orginAngle + cirAngle) % 360;
        return calcArcEndPointXY(cirX, cirY, radius, cirAngle);
    }

    /*
     * @param cirAngle 当前弧角度
     */
    public static PointF calcArcEndPointXY(float cirX, float cirY, float radius, float
            cirAngle) {
        float posX = 0.0f;
        float posY = 0.0f;
        // 将角度转换为弧度
        float arcAngle = (float) (Math.PI * cirAngle / 180.0);
        if (cirAngle < 90) {
            posX = cirX + (float) (Math.cos(arcAngle)) * radius;
            posY = cirY + (float) (Math.sin(arcAngle)) * radius;
        } else if (cirAngle == 90) {
            posX = cirX;
            posY = cirY + radius;
        } else if (cirAngle > 90 && cirAngle < 180) {
            arcAngle = (float) (Math.PI * (180 - cirAngle) / 180.0);
            posX = cirX - (float) (Math.cos(arcAngle)) * radius;
            posY = cirY + (float) (Math.sin(arcAngle)) * radius;
        } else if (cirAngle == 180) {
            posX = cirX - radius;
            posY = cirY;
        } else if (cirAngle > 180 && cirAngle < 270) {
            arcAngle = (float) (Math.PI * (cirAngle - 180) / 180.0);
            posX = cirX - (float) (Math.cos(arcAngle)) * radius;
            posY = cirY - (float) (Math.sin(arcAngle)) * radius;
        } else if (cirAngle == 270) {
            posX = cirX;
            posY = cirY - radius;
        } else {
            arcAngle = (float) (Math.PI * (360 - cirAngle) / 180.0);
            posX = cirX + (float) (Math.cos(arcAngle)) * radius;
            posY = cirY - (float) (Math.sin(arcAngle)) * radius;
        }
        return new PointF(posX, posY);
    }

颜色的渐变效果,即获取每个刻度所对应的颜色段内等比例的16进制颜色值,参考代码如下:

    /**
     * 通过刻度获取当前渐变颜色值
     * @param p 当前刻度
     * @param specialScaleCorlors 每个范围的颜色值
     * @return 当前需要的颜色值
     */
    public static int evaluateColor(int p, int[] specialScaleCorlors) {
        // 颜色范围
        int startInt = 0xFFbebebe;
        int endInt = 0xFFbebebe;
        float fraction = 0.5f;
        
        if(p != 0 && p != 100){
            startInt = specialScaleCorlors[p / 20];
            endInt = specialScaleCorlors[p / 20 + 1];
            fraction = (p - (p / 20) * 20) / 20f;
        }
        int startA = (startInt >> 24) & 0xff;
        int startR = (startInt >> 16) & 0xff;
        int startG = (startInt >> 8) & 0xff;
        int startB = startInt & 0xff;

        int endA = (endInt >> 24) & 0xff;
        int endR = (endInt >> 16) & 0xff;
        int endG = (endInt >> 8) & 0xff;
        int endB = endInt & 0xff;

        return (int) ((startA + (int) (fraction * (endA - startA))) << 24)
                | (int) ((startR + (int) (fraction * (endR - startR))) << 16)
                | (int) ((startG + (int) (fraction * (endG - startG))) << 8)
                | (int) ((startB + (int) (fraction * (endB - startB))));
    }

其余实现部分我就不细说了,很常规,具体的代码我都放在了gitHub上,有需要的可以clone or download。

gitHub - CustomViewCollection

mjzuo博客列表传送阵

发布了63 篇原创文章 · 获赞 191 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/MingJieZuo/article/details/84102221
今日推荐