本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点
进度条效果示意图自定义View是平时开发过程中逃不过的一劫,效果千变万化,唯有迎难而上,才能以不变应万变。
分析需求
这次碰到一个简单的需求,就是如上图的加载进度条。分析总结后就几条:
- 初始时是一圈虚线
- 进度开始时慢慢绘制实线
- 加载成功时加快实线的绘制,快速绘制完一圈表示成功
分析完需求,那我们就来想想怎么实现这个特殊的View。
准备工作
首先我们肯定先需要掌握基本的View的绘制,比如画笔Paint、画布Canvas,以及View的绘制原理等。
自定义View,其实可以这样简单来理解:假设我们自己拿笔去画这个图,我们会怎么画?会有哪些步骤?然后我们用学到的知识编写程序让计算机帮我们画。所以我们得先自己知道怎么去画才行。
这里我分析一下,可分为这几步:
- 先画一圈虚线
- 然后根据进度绘制实线
- 当收到加快进度的信号后快速绘制完一圈实线
这里就有几个点了:
- 怎么快速绘制出一圈虚线呢?
- 绘制实线怎么控制绘制的快慢呢?
- 怎么加快实线的绘制呢?
预备知识:
- Android自定义View之Paint绘制文字和线
- Android自定义View之Canvas
- Android自定义View之invalidate方法和postInvalidate方法
- Android自定义View注意事项
实践
这里我们采用继承View的方式来实现
画虚线
这里最简单的方式就是利用Paint的PathEffect属性,PathEffect属性用来控制画笔Paint的路径样式,比如虚线,折线的拐角圆滑等。
虚线对应的PathEffect为DashPathEffect,具体用法如下:
mRimPaint.setPathEffect(new DashPathEffect(new float[]{3f, 30f}, 0));
其中float数组用来控制虚线的效果,数组的第一个元素控制虚线的长短,第二个用来控制虚线之间的间隔,具体的效果大家可以动手试一下,这样子比较直观。需要注意的是float数组里面必须至少包含2个元素,并且必须是偶数个元素。
所以我们画一圈虚线就简单了:
//虚线画笔
mRimPaint = new Paint();
mRimPaint.setAntiAlias(true);
mRimPaint.setStyle(Paint.Style.STROKE);
mRimPaint.setColor(this.mRimColor);
mRimPaint.setStrokeWidth(this.mRimWidth);
mRimPaint.setStrokeCap(Paint.Cap.ROUND);
mRimPaint.setPathEffect(new DashPathEffect(new float[]{3f, 30f}, 0));
其中需要注意的是,setStrokeCap这个属性。我们设置的 Cap.ROUND 属性能让我们绘制出的线段更加圆滑。其他的属性在预备知识中都有介绍。
准备好画笔以后我们就可以开始绘制我们的虚线了,绘制当然需要在onDraw方法中
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(mCircleBounds, 360.0f, 360.0f, false, mRimPaint);
}
这里我们采用了Canvas的drawArc方法,就是绘制一段360度的圆弧。具体的参数属性可以参看上面预备知识中关于Canvas的文章。
其中需要注意的是第一个参数,也就是圆弧外框矩形的确定。这个矩形的作用就是确定整个图形的边界,因为我们的线段是有宽度的,所以在计算边界的时候需要考虑到线段的宽度。
实际上我们后面肯定要让这个进度条的一些属性能自定义,比如进度条的颜色,宽度等,所以我们在绘制的时候就需要考虑到进度条宽度的问题。
要解决这个问题也简单,在创建这个外框时,把进度条的宽度考虑进去就行了。具体看代码:
float circleWidthHalf = (float) this.mBarWidth / 2.0F > (float) this.mRimWidth / 2.0F ? (float) this.mBarWidth / 2.0F : (float) this.mRimWidth / 2.0F;
this.mCircleBounds = new RectF(paddingLeft + circleWidthHalf, paddingTop + circleWidthHalf, (float) width - paddingRight - circleWidthHalf, (float) height - paddingBottom - circleWidthHalf);
其中,mBarWidth是实线进度条的宽度,mRimWidth是虚线的宽度。由于实线和虚线可能宽度不一样,所以我们需要以较宽的为准。
画实线进度条
有了以上的基础,那画实线进度条就简单了。同样是先设置Paint,然后用drawArc方法绘制。
设置Paint属性
//实线画笔
mBarPaint = new Paint();
mBarPaint.setAntiAlias(true);
mBarPaint.setColor(this.mBarColor);
mBarPaint.setStyle(Paint.Style.STROKE);
mBarPaint.setStrokeCap(Paint.Cap.ROUND);
mBarPaint.setStrokeWidth(this.mBarWidth);
然后用Canvas的drawArc方法绘制
canvas.drawArc(this.mCircleBounds, (float) this.mStartAngle, degrees, false, this.mBarPaint);
这里绘制实线就需要特殊处理了,因为我们需要慢慢地绘制,而不是一次性的绘制出一个实线圆。这里的思路也很简单,就是随着时间的推移慢慢地绘制实线进度,只不过角度越来越大。
所以要有加载的进度效果,关键就是要控制绘制实线的角度了,那这个角度怎么确定呢?我们又怎么在角度改变时,实时刷新我们的View呢?
我们下次见分晓......
欢迎关注我的微信公众号,和我一起每天进步一点点!
AntDream
网友评论