今日产品经理让在产品里面加了个横向选择的功能,控件样子大致要求为:
网上找了好久没找到此控件,只能自己动手写了,很适合新手练习自定义View,并贡献给大家,效果如下:
其实很多滚轮控件也只是这个简单控件组合一下就可以了 。
实现思路
这里我偷懒了,没有把上、左、右三个箭头写到控件里面,写进去也简单,不过突然感觉在外面布局,写个方法出来也是蛮帅的。所以今天我们的主角就是中间的可以横向滑动的部分,乍一看就是个 recycleview,不过这里我没有想过要用 recycleview 来实现,不是不可以,是用 recycleview 的话,各种判断、计算偏移量太多了。
而且需求中要求只是文本,无需加载布局,所以为了节省时间就干脆自定义一个名为 HorizontalselectedView 的 View,宽高无需自己计算,只需在 onDraw() 方法里面把每个String 画出来, 然后监听滑动事件或者点击左右箭头的时候,重走onDraw()方法就可以了,难点在于 onDraw 的时候,每个 String 的坐标如何获得。
控件特征
1、中间箭头下面的文字(被选中的文字)颜色和字体和其他的不一样
2、可以横向左右滑动,滑动过程当中,被选中的文字在变化
3、点击左右箭头的时候也可以 实现滚动,从而改变被选中的文字
4、可见区域内,显示的文字数是可以改变的
5、左右滑动的时候有回弹选择效果
根据以上特征,就能得到我们所需要的自定义属性,如下:
在构造方法里面初始化画笔和属性:
重写onDraw()方法
所有的文字里面,被选中的文字是特殊的,他的大小和颜色不一样,所有我们先把他给画出来,关键点在于要测量文本的宽高,代码如下:
下面要做的是就是要遍历集合,把其他的文字给画出来,刚才也提到了,坐标是难点,我们看张图来理一理:
其实最巧妙的是得到图中所标注的一个单元的长度anInt,可见区域的长度除以可见个数就得到了 , 还有就是这个 n,给到数据源的时候,我是让数据源集合的长度除以2的,这个可以理解的。然后遍历集合的时候 就可以根据下面得到x的坐标:x=width/2+anInt*(i-n)-textWidth/2,这里面的 textWidth 我们默认他一样长了,但实际情况中,可能会出现三位数,四位数,三个字,四个字,所以在代码中,我是获得被选中文字左右两面长度的平均值得到的。
接下来就可以在 onDraw() 方法里面遍历了:
这样所得到的效果是把strings平铺在了控件上,其实已经有点样子了,下面就是进行滑动监听了。
触屏监听事件
触屏监听,自然而然就是要复写 onTouchEvent方法了 , 这里的触屏事件还是比较简单的,先贴上代码:
奇怪的是,在这里面打 log,只有 down事件 触发,move 和 up 事件触发不了,这就要加上一行代码:
setClickable(true);//使可点击
down 的时候记录下 downX 坐标值,然后 move 时根据 scrollX 和 downX 的大小判断向左还是向右
从而当 scrollX -downX 的绝对值刚好等于 anInt 的时候,n 相应的 加1 或者 减一 , 再进行重绘,继而把此时的 scrollX 赋值给 downX;
这就实现了左右滑动,这个时候,整个文本向右或者向左 一个单元一个单元的移动,这显然不是我们要的效果,我们要的是,滑动的过程当中,文本就跟着手势在动,所以这里面肯定需要个偏移量 offSet;
offset = scrollX - downX;
当移动一个单元长度的时候再把 offset 归零就可以了;所以最终每个文本的x坐标为:
这样就基本实现需求了,需要注意的是有几个地方需要加上 n 的大小判断的,不能让他小于0了,或者大于集合长度了,防止越界
对外提供的一些方法