一些心里话
自定义View作为Android程序开发过程中,初阶到中阶晋级的关键性标志,一直是很多Android程序员学习的必经之路,有很多同行在遇到自定义View后选择了知难而退,这就造成了一个现象,那就是这些程序员只会拿别人造好的轮子修修补补,而从不知道一个轮子该如何造出来,这样不好。
虽然我也不建议大家都重复的造轮子,毕竟你造出来的未必比别人好,造好了也花费大量时间,拖延了项目进度,但是知道如何造轮子这件事肯定是很重要的,不能因噎废食,毕竟自定义View涉及的知识点非常多且复杂,只有掌握了难度较高的技能,你才能在红利期已过的移动开发中走的更远,爬的更高,毕竟这个行业虽算不上弱肉强食,但是优胜略汰的自然法则还是有的。
好了,叭叭了这么多,目的不是说教,而是希望每个人都能看清自己未来的路,有所追求也学会取舍。
说说这个自定义View
自定义View其实没啥好说的,直接看效果图即可:
大概就是这个样子了,有几处需要简单说明一下:
1.可以自定义圆形的大小
2.可以自定义连接线的粗细
3.可以自定义完成和未完成的颜色
4.可以自定义阶段文字的大小
5.可以添加点击事件
6.支持设置进度线在两个圆形之间
(比如:设置步数为2.3,从0开始画点则会在点2和点3之间有一个完成度为百分之30的完成线)
基本上自定义View就是这个样子了,适合一些进度周期较短的业务,比如:周期较短的售后业务或者开发流程等进度轴。
自定义View的绘制思路
每做一个自定义View我们必须养成一个习惯,那就是先考虑绘制思路,自定义View的过程其实就是利用Android给的画笔(Paint)和自定义的属性值(attrs.xml)再根据一定的测量规则(onMeasure)以及绘制流程(onDraw)利用一些算法(贝塞尔曲线等)在画布(Canvas)上绘制的过程,所以在你不需要学习一些画画的基本功的前提下(Paint和Canvas都帮你做了),如何构图就成了一个程序员绘制自定义View的关键。
构图,看似触手可及但实际上虚无缥缈,这是一个创作的过程,创作就是痛苦的过程(天才除外)。
现在回到我们的自定义View吧,要绘制一个横向的进度轴,最关键的几个问题:
1.如何绘制点?
2.如何绘制线?
3.第一个点左边留白多少?
4.第二个点右边留白多少?
5.自定义测量的宽度和高度应该怎么计算?
问题其实不多,绘制点和线Canvas都有现成的方法,不用操心,关键是第一个点的左边留白和最后一个点的右边留白,因为我开始画的时候简单的认为只要留出圆形的半径就行了,结果发现下面的字比圆形宽的时候,字就超出界面了,所以得考虑字和半径的宽度,取比较宽的那个值进行留白,自定义测量的宽度和高度我是这么设计的:宽度为手机宽度,除非你写了具体值,高度为圆的直径加上两个字的高度再加上padding。
这样就把这个自定义View的框架搭建好了,然后考虑的就是如何连线以及如何画未完成的延长线了:
1.连线很简单,只要确定步数大于1,然后让总宽度减去左右留白的宽度和起始及结束两个圆的直径,剩下的宽度在除以点数-1来算出每条连接线的长度,再将线连接起来即可。
2.未完成进度的延长线的思路就是,得到这个步数最大的步数,在这个步数对应的圆形之后绘制一条连接线长度百分比长度的完成线覆盖即可。
当然还要考虑自定义View设置点击事件并对外提供接口以及点击事件判断点击点是否在时间轴的圆形上并重新绘制完成和未完成的界面等等。
这个思路写出来可能很难描述清楚,如果看不懂或者看迷糊了那肯定是我表达不好,不用担心,继续往下看,代码会告诉你一切,Talking Is Cheap!
代码如何实现
第一步:在values文件夹里加入attrs.xml文件,用来存放自定义View用到的自定义属性,主要目的是在布局文件中就可以设置自定义属性的值,方便开发者设置。
1 | <?xml version="1.0" encoding="utf-8"?> |
这个操作如果看不懂,就得自己去学了,主要学习自定义属性方面的知识。
第二步:开始编写自定义View的代码,融入刚才的思路,注释我已经写的非常好了(个人认为),请认真阅读,带着刚才我描述的稀里糊涂的思路也可以。
1 | /** |
第三步:布局文件 没啥可说的
1 | <?xml version="1.0" encoding="utf-8"?> |
第四步:如何使用 也没啥好说的 组件引入了ButterKnife,如果你没用,自己修改一下就可以了。
1 | public class TimeLineViewActivity extends AppCompatActivity { |
结语
代码不难,我用了一上午时间来写出了一个最简陋的DEMO,他可以完成基本需求即可,然后又用了一下午的时间来优化这些代码,完善一些思路和测试一些极端情况,这期间还有一些杂事去处理。
之所以写这个其实是想告诉大家,不要一口吃个胖子,自定义View一定要先根据思路写出基本代码来,然后一步步的优化,当然,如果你很熟悉了另当别论,这也只是我的开发风格而已。
谢谢你看完!