在城市列表的快速检索项目中,左侧的26个英文字母Bar是自己画出来的,因此暂且把这个小项目也归类到自定义View中吧。
项目逻辑:
1.左边是一个自定义从A-Z的快速索引,它能够获取到触摸它的时候获取到的字母的索引。
2.右边是一个ListView,按照字母分类排序里面的内容,并且根据触摸的字母,去自己列表找首字母和触摸字母相同的那个
item,然后让item放置到屏幕顶端(setSelection(position));
3.需要用到文字转拼音。
下面就开始来一步步的实现这个功能吧。
一、自定义26个字母索引View:QuickIndexBar
1)绘制文字:使用canvas.drawText(text,x,y,paint)来实现。其中x,y在默认情况下(Paint.Align.LEFT模式下)分别是所绘制的文字左下角的坐标。
![7753368-5ab91cf676f53a0a.png](https://img-blog.csdnimg.cn/img_convert/9758015bc385a00692345d39f7edc440.png)
通过上图可以分析出,画文字时的x,y坐标的值,x值就是自定义View宽度的一半:getMeasureWidth/2, y值是格子高度/2 + 文字高度/2 ,如果是B之后的字母,还需要加上格子的高度,因此,我们可以得到y值:格子高度/2 + 文字高度/2 + position*格子高度
在竖直方向上,我们要把26个字母平均分配到自定义View中,因此每个格子的高度是getMeasureHeight()/26,重点是求文本的高度。
获取x值和格子的高度:
![7753368-11e97e69981d5bdd.png](https://img-blog.csdnimg.cn/img_convert/e611e2b07442f56c6fdcf65fef382f4b.png)
在自定义View中用canvas绘制文字时,可以通过这样一个方法去获得文字的高度:
![7753368-8ca300dc4a532811.png](https://img-blog.csdnimg.cn/img_convert/2b3135cef85d1512084a2ca1fd5531b9.png)
定义一个矩形bounds,当这个方法执行完成之后,我们所要测量的文字就满满的填充在bounds之中,此时我们获取矩形的高度即可以得到文字的高度。
![7753368-4df6fd97bc30bdbb.png](https://img-blog.csdnimg.cn/img_convert/36be0f354e389facbd4dfa2ed407326f.png)
高度获取之后,我们就可以来绘制文字了。
初始化画笔,可以设置文字的大小,颜色等。
![7753368-6edae944c3eba7f6.png](https://img-blog.csdnimg.cn/img_convert/93a452738792d69fe9c6583a8a904a31.png)
![7753368-45ecabe0abb28c13.png](https://img-blog.csdnimg.cn/img_convert/b29fa77e20131b5092997fa8cb7c8b6a.png)
效果图:
![7753368-dcf9c74688a659a2.png](https://img-blog.csdnimg.cn/img_convert/ca69bc96b98a789c646881921348cd25.png)
2)按下和移动时计算触摸字母Bar时对应的字母值。(int)按下的y值/cellHeight就是字母的position,移动时也是这样一个逻辑,但是手指在屏幕上移动会产生无数个移动事件,这里就需要控制一下,只有当position改变时,才获取字母的值。
![7753368-c92780220efbc829.png](https://img-blog.csdnimg.cn/img_convert/a86b8dfa479d8118d25a6b4822a166b3.png)
实现每次选中的字母都会变色,在每一次移动,按下,抬起时都要重绘界面,在onDraw()中判断 lastIndex == i ,如果相等那么重绘时,把第i个字母的颜色改变,其他字母仍然是黑色。
![7753368-34c1b831454286fe.png](https://img-blog.csdnimg.cn/img_convert/558d9c983189a9ee18572322c3ce9df6.png)
3)设置回调,把每次获取的字母传出去,用于与外界的ListView的数据交互。
编写接口和setXXXListener()
![7753368-bb95bb0f63ba2516.png](https://img-blog.csdnimg.cn/img_convert/9cd782aa506da25b91b71197149e8f1c.png)
在获取字母的地方,调用接口中的方法,把数据传递出去。
![7753368-8cbeb518df660c4d.png](https://img-blog.csdnimg.cn/img_convert/a138e66bec1f8714ab484e7fec2b4964.png)
在外界获取数据。
![7753368-604e948624537568.png](https://img-blog.csdnimg.cn/img_convert/3ba039dc07a712274818797d788d6670.png)
这里有关于字母索引条的开发就完成了,下面开始左侧ListView的开发。
二、左侧ListView的开发
1)设置ListView的Item
左侧ListView的Item分为上下两部分,上部分是显示首字母,下部分是显示名称。如图,下部分填充的是姓名,上部分填充的是姓名的首字母。
![7753368-3008581a3eade7d2.png](https://img-blog.csdnimg.cn/img_convert/1713238dd2d487edbdd507fdaf1dd0ec.png)
2)将姓名转化成拼音,使用到的是pinyin4j.jar
![7753368-c1f0a554774cbe97.png](https://img-blog.csdnimg.cn/img_convert/325627e16884cf43e7d19a449024b787.png)
在Adapter中设置数据
![7753368-9e4ffa8b8c394199.png](https://img-blog.csdnimg.cn/img_convert/ee725a8aafb3b7cd7a2573087fe804bd.png)
此时效果图是这样的
![7753368-2a24590d1e78ab33.png](https://img-blog.csdnimg.cn/img_convert/75fcf063870563b1763af7039d4de2b5.png)
3)对姓名进行排序
使用Collections中的sort(),但是该方法要求参数中的实体类必须实现 Comparable<T>接口,实现其中的compareTo()
![7753368-7270cee7e4c377b7.png](https://img-blog.csdnimg.cn/img_convert/da2b256e152a9cb84d296c9ad0bdb24d.png)
![7753368-4fc128c7b238fafa.png](https://img-blog.csdnimg.cn/img_convert/ea2430d78741f52abf02715e1ce2e92a.png)
4)对于相同首字母的条目,item上部分显示字母的部分只留一个,其它隐藏起来。跟上一个Item比较,如果是相同的首字母就要隐藏上半部分
![7753368-dafa376fbe53f56f.png](https://img-blog.csdnimg.cn/img_convert/d04bf66c4b4de4a57ecdccdbc4d6f45f.png)
此时的效果图
![7753368-bd08a7d8d25e0d2f.png](https://img-blog.csdnimg.cn/img_convert/dda2bb7c48129e0f3e68a076bc1a5b93.png)
5)手指点击或移动到某个字母上,ListView会把相应首字母的Item放置屏幕的顶端
![7753368-3d789ca3c7c1dc56.png](https://img-blog.csdnimg.cn/img_convert/d6e587e781c38bc380582b65088027a2.png)
6)点击相应的字母,屏幕中间弹出对话框,这里屏幕中间的对话框使用TextView,没有点击的情况下,TextView是隐藏状态,当需要显示TextView时,显示出来
![7753368-996fe2b6725f8af2.png](https://img-blog.csdnimg.cn/img_convert/a7aecdf6d187d001255134b8ad676361.png)
效果图:
![7753368-78a5826a4569f918.gif](https://img-blog.csdnimg.cn/img_convert/182f00287ef86826bc8feaa15c3b8925.gif)