简单的圆形的进度条

很久没有发博客了,准备从现在开始多写多发,把自己平时遇见的坑和心得一点点记录下来,算是记录自己的成长吧。
话不多说,今天分享的是圆形进度条的实现思路。源于公司之前要实现的一个控件,当时可是费了我一番心思才找到实现方式。上效果图
这里写图片描述
这个效果的实现主要是使用到了Canvas的一个属性,叫PorterDuffXfermode,这个属性可以将所绘制的图形的像素与Canvas中对应位置的像素按照一定规则进行混合,形成新的像素值,以实现如取交集等许许多多有趣的效果,
有兴趣的人可以参考一下这篇博客
Android中Canvas绘图之PorterDuffXfermode使用及工作原理详解
讲解的十分清楚。
我们来看看实现思路,首先,我们在底部画一个圆
这里写图片描述
然后,再这个圆的上方画一个矩形,覆盖圆的下半部分,作为进度条,如图
这里写图片描述
然后,我们将超出圆形部分的矩形消除,只显示相交部分(打叉的部分消除)这里写图片描述
然后我们在代码里实现我们的功能
首先,定义我们需要用到的对象,然后初始化它

    /**
     * 剩余百分比
     */
    private float progress;
    /**
     * 圆的半径
     */
    private float radius;
    /**
     * 背景圆画笔
     */
    private Paint circlePaint;

    /**
     * 进度的画笔
     */
    private Paint progressPaint;

    public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public CircleProgressView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CircleProgressView(Context context) {
        super(context);
        init();
    }

    /**
     * 初始化
     */
    private void init() {
        radius = 400;
        circlePaint = new Paint();
        // 抗锯齿
        circlePaint.setAntiAlias(true);
        circlePaint.setColor(0xffff0000);
        circlePaint.setStyle(Style.FILL);

        progressPaint = new Paint();
        progressPaint.setAntiAlias(true);
        progressPaint.setColor(0xff00ff00);
        progressPaint.setStyle(Style.FILL);
        // 设置Mode,使超出界限的部分不显示在屏幕上,并且相交部分显示上部
        progressPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));

    }

可以看到,我们为用于画进度的画笔progressPaint设置了一个属性,progressPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
这个属性的意思是,用这个画笔画出来的图形,和下方的图形取交集,并且用它的颜色值替换下方图形的颜色值,用来实现我们上分所说的将超出部分隐藏的需求。
接着,我们看看onDraw(Canvas canvas)方法

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int canvasWidth = canvas.getWidth();
        int canvasHeight = canvas.getHeight();
        int layerId = canvas.saveLayer(0, 0, canvasWidth, canvasHeight, null, Canvas.ALL_SAVE_FLAG);
        // 画背景圆
        canvas.drawCircle(radius, radius, radius, circlePaint);
        // 画进度
        canvas.drawRect(0, 2 * radius * (1 - progress), 2 * radius, 2 * radius, progressPaint);

        canvas.restoreToCount(layerId);
    }

首先,通过canvas.saveLayer()新建一个透明的layer,新建的layer放置在canvas默认layer的上部,当我们执行了canvas.saveLayer()之后,我们所有的绘制操作都绘制到了我们新建的layer上,而不是canvas默认的layer。
然后我们在这个layer上画背景圆,画代表进度的矩形,然后调用restoreToCount(layerId)将该layer绘制到canvas默认的layer上面。
然后我们的功能就实现啦。
完整的代码如下

/**
 * @author liuhuiqiang
 */
public class CircleProgressView extends View {
    /**
     * 剩余百分比
     */
    private float progress;
    /**
     * 圆的半径
     */
    private float radius;
    /**
     * 背景圆画笔
     */
    private Paint circlePaint;

    /**
     * 进度的画笔
     */
    private Paint progressPaint;

    public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public CircleProgressView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CircleProgressView(Context context) {
        super(context);
        init();
    }

    /**
     * 初始化
     */
    private void init() {
        radius = 400;
        circlePaint = new Paint();
        // 抗锯齿
        circlePaint.setAntiAlias(true);
        circlePaint.setColor(0xffff0000);
        circlePaint.setStyle(Style.FILL);

        progressPaint = new Paint();
        progressPaint.setAntiAlias(true);
        progressPaint.setColor(0xff00ff00);
        progressPaint.setStyle(Style.FILL);
        // 设置Mode,使超出界限的部分不显示在屏幕上,并且相交部分显示上部
        progressPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int canvasWidth = canvas.getWidth();
        int canvasHeight = canvas.getHeight();
        // 新建一个透明图层
        int layerId = canvas.saveLayer(0, 0, canvasWidth, canvasHeight, null, Canvas.ALL_SAVE_FLAG);
        // 画背景圆
        canvas.drawCircle(radius, radius, radius, circlePaint);
        // 画进度
        canvas.drawRect(0, 2 * radius * (1 - progress), 2 * radius, 2 * radius, progressPaint);

        canvas.restoreToCount(layerId);
    }

    public void setProgress(float progress) {
        this.progress = progress;
        postInvalidate();
    }

}

然后我们在这个基础上改一改就可以做出很多绚丽的效果了,比如360的加速球
这里写图片描述
新手上路,如果有错漏的地方,欢迎指正

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值