前言
WheelView想必大家或多或少都有一定了解, 它是一款3D滚轮控件,效果类似IOS 上面的UIpickerview 。按照国际惯例,先放一张效果图:
以上是Android-PickerView 的demo演示图,它有时间选择和选项选择,并支持一二三级联动,支持自定义样式。由于saiwu-bigkoo(吴哥)已经转行不干编程了,项目现由我主导更新维护。目前我更新了3.x + 的版本,修复了若干问题,并重构了项目,让开发者使用起来更加灵活方便,定制化更强。另外我还创建了一个组织,希望有兴趣的小伙伴也能加入进来为这个项目添加一份力量。在这里特别要感谢各位使用者提的建议和Issue,以及为这个项目贡献代码的伙伴们 totcw、saiwu-bigkoo。关于它的介绍和使用详情,这里就不过多阐述,有兴趣请参考我的另外一篇文章:Android-PickerView系列之介绍与使用篇(一)
好了,闲话就说到这,开始进入正文,本篇文章的主要内容是讲解WheelView的实现原理以及源代码,大致分以下几个步骤:
一、实现原理
二、自定义控件
三、onMeasure 测量
四、onDraw 绘制
五、onTouchEvent监听
一、实现原理
上面我们看到的GIF图中,控件中间滚轮部分的布局,有多个WheelView, 一个WheelView 就是一个3D滚轮,我画了一张图方便大家更为直观地理解:
从上图中我们可以看到,每一项Item都是在圆弧上面, 假设我们设置的WheelView它的可见Item数目为11,那么圆的半个周长就等于 10项Item的高度。我们看到的第一象限和第四象限,它是可见区域,即Item所显示的位置。其中,每项Item的高度 ItemHeight 等于两条分隔线的高度,具体如下图所示:
(为什么要画得那么详细,因为这些参数在绘制过程中需要用到)
因此,我们可得以下结论:
1.每项Item 的高度是由文字大小以及间距倍数控制的, itemHeight = lineSpacingMultiplier * maxTextHeight;
2.圆周长 C = 2 (itemHeight *(itemsVisible - 1))
2.根据圆周长公式 C= 2πR, 可推导出圆半径R = C/2π ,圆直径 L = C/π;
二、自定义控件
- 创建一个WheelView 类继承自 View,覆盖onDraw、onMeasure、onTouchEvent方法.
- 在构造方法中初始化数据;
- 在构造方法中初始化三个画笔Paint,分别用于绘制选中项、未选中项、分隔线。
private void initPaints() {
paintOuterText = new Paint();
paintOuterText.setColor(textColorOut);
paintOuterText.setAntiAlias(true);
paintOuterText.setTypeface(Typeface.MONOSPACE);
paintOuterText.setTextSize(textSize);
paintCenterText = new Paint();
paintCenterText.setColor(textColorCenter);
paintCenterText.setAntiAlias(true);
paintCenterText.setTextScaleX(1.1F);
paintCenterText.setTypeface(Typeface.MONOSPACE);
paintCenterText.setTextSize(textSize);
paintIndicator = new Paint();
paintIndicator.setColor(dividerColor);
paintIndicator.setAntiAlias(true);
if (android.os.Build.VERSION.SDK_INT >= 11) {
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
}
三、onMeasure 测量
1.计算最大length的Text的宽高度
private void measureTextWidthHeight() {
Rect rect = new Rect();
for (int i = 0; i < adapter.getItemsCount(); i++) {
String s1 = getContentText(adapter.getItem(i))