// 画上线。第一个item不画
if (i != 0) {
c.drawLine(xPosition, itemView.top.toFloat(),
xPosition, itemView.top.toFloat() + offset, paint)
}
// 画下线。最后一个item不画
if (i != count - 1) {
c.drawLine(xPosition, itemView.top + radius * 2 + offset,
xPosition, itemView.bottom.toFloat(),paint)
}
// 画圆
c.drawCircle(xPosition, itemView.top + offset + radius, radius, paint)
}
}
override fun getItemOffsets(outRect: Rect, view: View, : RecyclerView, state: RecyclerView.State) {
super.getItemOffsets(outRect, view, parent, state)
// 设置item在左边的偏移量
outRect.left = radius.toInt() * 2
}
}
现在我们可以来定义一个虚拟的数据源Record
,把这个ItemDecoration
应用到一个RecyclerView
上康康效果:
rv_timeline1.adapter = RecordAdapter(ArrayList())// 省略构造假数据
rv_timeline1.addItemDecoration(FirstVerTimeline())
复制代码
已经初具规模了!只是时间线和文字之间挤了一点,我们只需要加上一些合适的padding,换一下测试数据,看起来就会像真的一样了!
为了从图1到达图2,我们需要做:
-
定义
paddingLeft
和paddingRight
属性,用来表示轴线的左右padding -
修改
getItemOffsets
为outRect.left = paddingLeft + paddingRight + radius.toInt() * 2
,留出偏移量的位置 -
修改
xPosition
的初始值为radius + paddingLeft
,改变轴线的x坐标
到这里第一个版本就算完成啦,第二个版本会有什么新功能呢
第二版
小庄打算在第二版里实现状态的不同颜色。为了实现这个需求,他陷入了深深的沉思:
-
数据类中肯定不可能耦合颜色这种UI实现,所以需要一个由状态获取颜色的办法
-
由于画一个
item
还需要知道上一个item
的颜色,干脆直接把整个数据源列表data
传入ItemDecoration
好了 -
结合以上两点,我们可以定义一个函数类型的属性
var color: (item: T) -> Int
,实现这个属性就可以让使用者通过数据状态设置想要的颜色了
函数类型是kotlin(或者说函数式编程)的特性之一。如果是Java的话可以考虑用模板模式实现,即定义一个抽象方法让子类去重写
class SecondVerTimeline : RecyclerView.ItemDecoration() {
// 其他属性…
var data: List = ArrayList() //–>这里有更新,定义了数据源
var color: (item: T) -> Int = { _ -> Color.GRAY } //–>这里有更新,通过这个属性设置颜色选择策略
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDraw(c, parent, state)
val count = parent.childCount
for (i in 0 until count) {
// …
val adapterPosition = parent.getChildAdapterPosition(itemView) //–>这里有更新,获取当前项的真正位置
val item = data[adapterPosition] //–>这里有更新,获取当前项的数据源
// 画上线。第一个item不画
if (adapterPosition != 0) {
paint.color = color(data[adapterPosition - 1]) //–>这里有更新,设置上线的颜色
c.drawLine(…)
}
paint.color = color(item) //–>这里有更新,设置圆和下线的颜色
// 画下线。最后一个item不画
if (adapterPosition != data.size - 1) {//–>这里有更新,改用数据源的大小判断是否为最后一个item
c.drawLine(…)
}
// 画圆…
}
}
// getItemOffsets…
}
代码中可能需要注意的点:
-
绘制上线前,需要通过
data数据源
获取到上一个item
,并用color属性
获得其状态对应的颜色 -
绘制圆和下线前,同样需要改变到
这一个item
的颜色 -
用
parent.childCount
获取到的子项数量指的是屏幕中可见的部分,必须要用parent.getChildAdapterPosition
获取到该项在列表中的真正位置,才能确定下线要不要画。否则会出现【当前屏幕上可见的最后一项不是真正的最后一项,但它却没有下线,但向下滑动后它又有下线了】的尴尬场景 -
注意到此时用于判断是否为最后一个
item
的方法,从count - 1
变为了data.size - 1
,用数据源的大小判断,比count
更加准确(原因同上一条)
使用时也需要有一些变化:
-
把
data
设置给ItemDecoration
-
通过
color
属性设置颜色策略
val secondVerTimeline = SecondVerTimeline()
secondVerTimeline.data = records
secondVerTimeline.color = { item ->
when (item.status) {
1 -> color1
2 -> color2
…
}
}
rv_timeline2.addItemDecoration(secondVerTimeline)
然后就可以运行看一下效果了:
哇哦,鹅妹子嘤,这样就已经实现根据状态转变颜色的功能了!第二版的功能也圆满实现!
=====================================================================
最后
只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。
真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。
腾讯、字节跳动、阿里、百度等BAT大厂 2019-2021面试真题解析
资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
)]
资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!