就在昨天美团点评技术团队已经将其热修复项目Robust的项目上传到了github,估计今天就会被朋友圈刷屏了,所以机智的我首先推荐一波~
新一代热更新系统Robust,对Android版本无差别兼容。无需发版就可以做到随时修改线上bug,快速对重大线上问题作出反应,补丁修补成功率高达99.9%。
https://github.com/Meituan-Dianping/Robust
本文由
丶小嵩
投稿。
丶小嵩
的博客地址:
http://blog.csdn.net/qq_22393017
WheelView想必大家或多或少都有一定了解, 它是一款3D滚轮控件,效果类似iOS 上面的UIpickerview 。按照国际惯例,先放一张效果图:
以上是Android-PickerView 的demo演示图,它有时间选择和选项选择,并支持一二三级联动,支持自定义样式。
由于原作者saiwu-bigkoo(吴哥)已经转行不干编程了,他已把项目转交由我更新维护。目前我更新了3.x的版本,修复了若干问题,并重构了项目,新增了许多可选参数,让开发者使用起来更加灵活方便,定制化更强。另外我还创建了一个组织,希望有兴趣的小伙伴也能加入进来为这个项目添砖加瓦。在这里特别要感谢各位使用者提的建议和Issue,以及为这个项目贡献代码的伙伴们
totcw
、
saiwu-bigkoo
。
关于它的介绍和使用详情,这里就不过多阐述,有兴趣请参考我的另外一篇文章:Android-PickerView系列之介绍与使用篇(一)
(
http://blog.csdn.net/qq_22393017/article/details/58099486
)
好了,闲话就说到这,开始进入正文,本篇文章的主要内容是讲解WheelView的实现原理以及源代码,大致分以下几个步骤:
自定义控件
onMeasure 测量
onDraw 绘制
onTouchEvent监听
上面我们看到的GIF图中,控件中间滚轮部分的布局,有多个WheelView, 一个WheelView 就是一个3D滚轮,我画了一张图方便大家更为直观地理解:
从上图中我们可以看到,每一项Item都是在圆弧上面, 假设我们设置的WheelView它的可见Item数目为11,那么圆的半个周长就等于 10项Item的高度。我们看到的第一象限和第四象限,它是可见区域,即Item所显示的位置。
其中,每项Item的高度 ItemHeight 等于两条分隔线的高度,具体如下图所示:
(为什么要画得那么详细,因为这些参数在绘制过程中需要用到)
因此,我们可得以下结论:
每项Item 的高度是由文字大小以及间距倍数控制的, itemHeight = lineSpacingMultiplier * maxTextHeight;
圆周长 C = 2 (itemHeight *(itemsVisible - 1))
根据圆周长公式 C= 2πR, 可推导出圆半径R = C/2π ,圆直径 L = C/π;
自定义控件
创建一个WheelView 类继承自 View,覆盖onDraw、onMeasure、onTouchEvent方法.
在构造方法中初始化数据;
在构造方法中初始化三个画笔Paint,分别用于绘制选中项、未选中项、分隔线。
onMeasure 测量
1.计算最大length的Text的宽高度
2.计算圆的半径和直径,求出WheelView控件的宽高度
3.计算两条分隔线和Label文字的基线位置
对于centerY 为什么要减去CENTERCONTENTOFFSET(偏移量),因为Canvas.drawText方法中的坐标参数Y,并不是文字的底部位置,而是基线位置,所以我们要微调一下位置,让显示居中:
注:图片来源于:
http://blog.csdn.net/zly921112/article/details/50401976
4.初始化默认显示的item的position,即选中项位置
onDraw 绘制
经过以上几个步骤之后,我们绘制控件所需要的各个属性值也基本上计算好了,接下来就开始在onDraw方法中进行绘制
1.绘制两条横线
2.绘制Label文字
3.绘制item内容文字
终于到最核心的地方了——绘制有3D滚轮效果的Item文字。绘制它的两个关键因素:
item平移距离translateY。
文字Y轴的缩放率 scaleY。
在绘制之前,我们需要温习一下 弧和圆、弧度、以及三角函数等概念以及它们的计算公式,对于公式有不了解的地方可以自行google 百度一下,这里就不多阐述了:
弧度和角度的换算公式 α = n*π/180 (α为弧度,n为角度)
弧度的计算公式 α = L / R ( 弧长/半径 )
正弦和余弦转换公式 cosα = sin( π/2-α )
由于我们在onDraw方法里面,translateY和scaleY都是是通过弧度 α 计算得到的,因此需要从弧度α开始入手。
由计算公式 α = L / R 可知,我们若要得到某项Item的弧度,则需要知道弧长和半径,半径之前我们已经同计算获取到了值,所以现在需要计算弧长。
弧长L = itemHeight * counter - itemHeightOffset;
即 Item的高度乘以该项Item所在Position位置,再减去已滑动距离的偏移量(itemHeightOffset < itemHeight ),计算出了弧长L,则可计算出每项Item对应的弧度α,计算出了α之后,根据三角函数可计算出平移距离translateY,如下图 :
radius (半径)
h2=cosα * maxTextHeight/2
h1=sinα * radius
由上图可知,item从位置F3E3移动到 A2B2的时,平移距离 translateY = radius - h2 -h1;
求出了translateY 之后,我们还需要求出scaleY:
由上图可知 scaleY = cosn,由于代码里面参数是弧度制代表的数值,所以我们用弧度制表达 scaleY = cosα;
计算好了,我们开始撸代码,由于篇幅问题,就只贴出了部分关键代码,如下:
“等等,大兄弟,刚刚不是说‘scaleY = cosα ’吗”,怎么缩放文字的代码是这样的:
canvas.scale(1.0F, (float) Math.sin(radian));
别急别急,这是由于为了使Item的显示位置处于第一象限及第四象限,我们把半圆以Y轴为轴心向右转90度了。所以我们的角度 angle = (float) (90D - (radian / Math.PI) * 180D);(使角度的取值范围为[-90°, 90°])
1.弧度和角度转换公式 α = angle*π/180
2.正弦和余弦转换公式 cosα = sin( π/2-α )
我们就把cos函数 给转化成sin函数了。
4.文字自适应大小
由于item的文字长度是不固定的,所以会存在文字长度过长而导致绘制超过Wheelview的宽度,因此这里需要做一下处理,当文字长度超过measuredWidth的时候,重设字体大小让其能完全显示:
onTouchEvent监听
一次静态图形绘制完成了,但是我们需要根据滑动距离让item文字动态地变换,以达到需求,那么如何根据滑动距离来控制UI变化呢?
别着急,之前已经说了定义WheelView 的时候需要覆盖onTouchEvent方法,必然是有它的道理的。我们通过onTouchEvent方法,然后:
分别处理MotionEvent.ACTION_DOWN、ACTION_MOVE、ACTION_UP 这三个事件,获取到滑动距离并记录下来。
根据获取的滑动距离、计算停止滑动时item所需要的偏移量 ,边界处理等工作。
最后调用invalidate()方法通知系统更新UI,相当于重新调用了onDraw()方法,重新绘制UI,实现3D滚轮效果。
由于篇幅问题,就只贴一下部分关键代码了:
以上是WheelView的实现原理以及绘制过程的讲解,但是实际使用中我们往往需要多个Wheelview 并设置联动来实现我们的功能,所以Android-PickerView,这个项目就是对其进行了很好的封装,提供了两种选择器,一种是时间选择器(timePicker),一种是选择选择器(optionPicker)。
完整项目代码请到Github下载,这里是地址链接:
https://github.com/Bigkoo/Android-PickerView
优秀人才不缺工作机会,只缺适合自己的好机会。但是他们往往没有精力从海量机会中找到最适合的那个。
100offer 会对平台上的人才和企业进行严格筛选,让「最好的人才」和「最好的公司」相遇。
扫描下方二维码,注册 100offer,谈谈你对下一份工作的期待。一周内,收到 5-10 个满足你要求的好机会!
如果你有
想学习的文章
直接留言,我会整理征稿。如果你有好的文章想和大家分享欢迎投稿,直接向我投递
文章链接
即可。
欢迎
长按下图
->
识别图中二维码
或者
扫一扫
关注我的公众号:
返回搜狐,查看更多
责任编辑:
平台声明:该文观点仅代表作者本人,搜狐号系信息发布平台,搜狐仅提供信息存储空间服务。