一个简单又不简单的进度条

作者: GoMoon | 来源:发表于2019-10-16 14:38 被阅读0次

    前言

    要求的效果是这样的


    progress_view.gif

    粗看之下,好像挺简单的,先画背景、再画进度条、最后画文字,就可以了。
    但细看之下,有坑,当文字的颜色和进度条相融时,还要从绿色变成白色,这可不好做。
    还好Androd是有解决方案的,就是利用图形学里一个概念——PorterDuff.Mode。

    PorterDuff是啥

    本着学英语的态度,笔者去翻译了一下这个单词,然而并没有结果,查了资料才发现,这个单词是两个人名的组合:Thomas Porter 和 Tom Duff,这两位大神是研究图形混合的。说到这里大家应该能明白了,PorterDuff.Mode其实就是两种或多种图形混合在一起时的各种模式,这里有16种Mode,看下图(蓝色方块是Src即源图,黄色圆形是Dst即目标图):


    proter-duff.png

    分析

    那么,如何借助PorterDuff来实现我们想要的进度条效果呢?
    这里需要绘制四个图层:最底层为灰色背景,其上为绿色进度条,最上面两个图层就要用到PorterDuff。
    我们可以选用SrcATop这种混合模式,按照官方解析,在SrcATop模式下,Src图像像素不覆盖Dst图像像素的部分直接丢弃 ,Src图像像素剩余部分绘制在Dst图像像素之上。所以,我们可以让绿色的文字为Dst,然后最上层画一层白色的进度条,不相交时不起作用,相交时只显示为Src的颜色,文字也就变成了白色。

    代码

    代码比较简单,直接贴在下面吧。

    public class ProgressView extends View {
        /**
         * 圆角弧度
         */
        private static final int RADIUS = 60;
    
        private Paint mPaint = new Paint();
    
        private int mProgress;
    
        public ProgressView(Context context) {
            this(context, null);
        }
    
        public ProgressView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public void setProgress(int progress) {
            if (progress >= 0 && progress <= 100) {
                mProgress = progress;
                invalidate();
            }
        }
    
        @SuppressLint("DrawAllocation")
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            int width = getMeasuredWidth();
            int height = getMeasuredHeight();
            //画底部背景
            mPaint.setColor(Color.LTGRAY);
            canvas.drawRoundRect( new RectF(0, 0, width, height), RADIUS, RADIUS, mPaint);
            //画进度条
            mPaint.setColor(getResources().getColor(R.color.colorPrimary));
            canvas.drawRoundRect(new RectF(0, 0, width * ((float) mProgress / 100), height), RADIUS, RADIUS, mPaint);
            //画文字图层
            mPaint.setColor(getResources().getColor(R.color.colorPrimary));
            mPaint.setTextSize(sp2px(getContext(), 20));
            mPaint.setTypeface(Typeface.DEFAULT_BOLD);
            mPaint.setTextAlign(Paint.Align.CENTER);
            Bitmap textBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            Canvas textCavas = new Canvas(textBitmap);
            String content = mProgress + "%";
            float textY = height / 2.0f - (mPaint.getFontMetricsInt().descent / 2.0f + mPaint.getFontMetricsInt().ascent / 2.0f);
            textCavas.drawText(content, width / 2.0f, textY, mPaint);
           //画最上层的白色图层,未相交时不会显示出来
            mPaint.setColor(Color.WHITE);
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
            textCavas.drawRoundRect(new RectF(0, 0, width * ((float) mProgress / 100), height), RADIUS, RADIUS, mPaint);
            //画结合后的图层
            canvas.drawBitmap(textBitmap, 0, 0, mPaint);
            mPaint.setXfermode(null);
            textBitmap.recycle();
        }
    
        public static int sp2px(Context context, float spValue) {
            final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
            return (int) (spValue * fontScale + 0.5f);
        }
    }
    

    相关文章

      网友评论

        本文标题:一个简单又不简单的进度条

        本文链接:https://www.haomeiwen.com/subject/ibaymctx.html