ContactList是仿通讯录制作的一个app demo
主要技术点在RecyclerView,和自定义view
界面概览:
概要
如图,主要简单划分为两个部分:
数据源、与界面组件。
数据源主要来自手机的通讯录信息,通过ContentResolver获取。
而界面组件主要有显示列表和侧边栏。而重点在于列表的分组栏的绘制与现实,这就依靠ItemDecoration来进行实现了,这也是难点。
复用方法
FloatingBarItemDecoration传入需要绘制标题栏的position和标题String的map,目前只支持竖项、单列的列表,如需要扩展,请读完此文,明白原理后很容易实现。
IndexBar传入Label的List,通过setListener加入勾子。
FloatingBarItemDecoration
An ItemDecoration allows the application to add a special drawing and layout offset to specific item views from the adapter’s data set. This can be useful for drawing dividers between items, highlights, visual grouping boundaries and more.
ItemDecoration主要是用来对RecyclerView进行一些修饰,是对adapter数据集中的数据视图增加修饰或空位。经常被用来画分割线、强调效果、可见的分组边界等。
getItemOffset()
1 |
|
绘制间距,为绘制标题栏空出间隙。主要逻辑是通过当前view的position判断是否需要在上方空出矩形范围。
onDraw()
主要是进行静态标题栏等绘制,即在每组view的上方,即getItemOffset()的区域进行标题栏的绘制。
1 |
|
onDrawOver
实现悬浮分组栏,以及悬浮分组栏碰撞效果绘制。
对于整个列表的绘制流程,是遵循如下的顺序:
ItemDecoration#onDraw() -> ItemView的绘制 -> ItemDecoration#onDrawOver
故而在onDrawOver中实现可以满足“悬浮”,即在最上层的效果。
1 |
|
IndexBar
IndexBar是侧边栏的实现,是采用的自定义View的形式。
FontMatrics
在此之前,介绍一个概念FontMatrics,是表征字体的一个矩阵。
定义BaseLine为Text的起始点(类似英文五线谱的baseline)
drawText传入的纵坐标值也为BaseLine所在的纵坐标,而非矩形区域的左下角的纵坐标(这点很重要,否则在开发者模式中开启布局边界会发现字体和边界错乱)
主要有以下几个属性:
- Top (<0)
- Ascent可能的最小值(绝对值最大)
- Ascent (<0)
- 字体最高处距BaseLine的距离
- Descent (>0)
- 字体最低处距BaseLine的距离
- Bottom (>0)
- Descent可能的最大值
- Leading
- 间距,用于多行文字显示时的距离
在此例中我们用来计算每个text的高度,以此作为测量View高度的参数。很多时候可以选择不加leanding值, 因为单行多行时候的leading值都为0.(不知道什么时候可以取到非0的值)
1 | Paint.FontMetrics fm = mPaint.getFontMetrics(); |
onMeasure()
计算View的长宽。
1 |
|
onDraw()
负责绘制
1 | protected void onDraw(Canvas canvas) { |
DispatchTouchEvent()
处理交互事件,主要是监听UP、CANCEL、DOWN、MOVE,其中以DOWN做为起点,CANCEL、UP做为终点,其他为中间状态。以TAG的焦点变更和事件的开始、结束做为重绘的触发点。
1 |
|
ContactsUtils
主要是负责获得缩写,其中英文字符就直接获得英文字符,中文字符通过比对GB2312得到英文缩写
对于中文获得缩写的核心思想如下,是通过比对GB2312值得到中文中声母,继而获得缩写情况。
1 | //GB2312中简体中文的起止,判断范围 |
ContactsManager
负责通讯录信息的获取,此处只取了电话号码和联系人名称,使用的是ContentResolver进行查询
1 |
|