自定义圆形进度条

来源:互联网 发布:java js解析器 编辑:程序博客网 时间:2024/06/08 13:24

自定义圆形进度条

公司之前有个圆形进度条的需求,先上一张效果图看一下。

样图

setting_bar_bg

setting_bar

外部能够提供给我的资源已经到此为止了,那么现在要想一想该怎么实现了。

进度为0的时候,显示的是一个完成灰色的圆形图片,随着数值的增大,进度条逐渐变成深黄色的圆形图片。

那么实现此功能的步骤


  • 绘制底部图片到界面上
  • 绘制的过程是一个扇形逐渐变成圆
  • 画文字到圆的中间
  • 既然要实现进度条,为了方便直接继承ProgressBar

绘制的过程中需要用到”Xfermode” 其实就是 “Transfer mode”,用 “X” 来代替 “Trans” 是一些美国人喜欢用的简写方式。严谨地讲, Xfermode 指的是你要绘制的内容和 Canvas 的目标位置的内容应该怎样结合计算出最终的颜色。但通俗地说,其实就是要你以绘制的内容作为源图像,以 View 中已有的内容作为目标图像,选取一个 PorterDuff.Mode 作为绘制内容的颜色处理方案—— [ HenCoder Android开发进阶 ]

代码

  • 初始化
    public CircleView(Context context) {        super(context);        init();    }    public CircleView(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    private void init() {        //获取资源图片        bmpBg = BitmapFactory.decodeResource(getResources(), R.drawable.setting_bar_bg);        bmpBefore = BitmapFactory.decodeResource(getResources(), R.drawable.setting_bar);        //得到灰色图片的宽高        width = bmpBg.getWidth();        height = bmpBg.getHeight();        //设置Alpha 合成模式        mMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);        //画扇形的笔        mPaint = new Paint();        mPaint.setXfermode(mMode);        mOval = new RectF();        mOval.left = 0;        mOval.top = 0;        progress = 0;        //画文字的笔        textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        textPaint.setColor(Color.DKGRAY);        textPaint.setTextSize(100);    }

PorterDuff.Mode.SRC_IN :在两者相交的地方绘制目标图像,并且绘制的效果会受到源图像对应地方透明度的影响

具体的情况是这个样子的,如下图:

绘制图片的例子

  • 测量控件的宽高
 @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        widthMeasureSpec = width;        heightMeasureSpec = height;        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);    }
  • 画出控件
 @Override    protected void onDraw(Canvas canvas) {        //将灰色图片绘制到画布上        canvas.drawBitmap(bmpBg, 0, 0, mPaint);        //绘制扇形需要设置矩形的位置信息        mOval.left = 0;        mOval.top = 0;        mOval.right = bmpBg.getWidth();        mOval.bottom = bmpBg.getHeight();        //使用离屏缓冲把内容绘制在额外的层上,再把绘制好的内容贴回 View 中        int saveCount = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);        //画扇形        canvas.drawArc(mOval, -90, 360 * progress / 100, true, mPaint);        //设置模式        mPaint.setXfermode(mMode);        //将黄色的进度条图片绘制出        canvas.drawBitmap(bmpBefore, 0, 0, mPaint);        //用完及时清除 Xfermode        mPaint.setXfermode(null);        //恢复图层        canvas.restoreToCount(saveCount);        //设置文字的对齐方式        textPaint.setTextAlign(Paint.Align.CENTER);        canvas.drawText(progress + "%", width / 2, height / 2 + 20, textPaint);    }

关于离屏缓冲(Off-screen Buffer)建议大家去看 [ HenCoder Android开发进阶 ] [2]这里有详细的介绍

  • 外部调用进度条的接口
    /**     * 设置进度的最大值     *     * @param max     */    public synchronized void setMax(int max) {        if (max < 0) {            throw new IllegalArgumentException("max not less than 0");        }        this.max = max;    }    public synchronized int getMax() {        return max;    }    /**     * 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步 刷新界面调用postInvalidate()能在非UI线程刷新     *     * @param current     */    public synchronized void setProgress(int current) {        if (current < 0) {            throw new IllegalArgumentException("progress not less than 0");        }        if (current > max) {            current = max;        }        if (current <= max) {            this.progress = current;            postInvalidate();        }    }    /**     * 获取进度.需要同步     *     * @return     */    public synchronized int getProgress() {        return progress;    }

到此为止绘制的工作已经做完了,那么让我们看一下效果。
这里写图片描述

从上面的效果图我们发现,刚刚进去的时候,会先显示一个黑色背景。/(ㄒoㄒ)/~~

原因是我们绘制灰色背景进度条之前,没有去清除Xfermode。所以加一行代码,再看效果。

mPaint.setXfermode(null);        //将灰色图片绘制到画布上        canvas.drawBitmap(bmpBg, 0, 0, mPaint);

这里写图片描述

好了,一个简单的自定义进度条就完成了。O(∩_∩)O~