第一版

第一个版本,小庄打算只实现画出圆和线的形状,没有状态也没有颜色,主要为了验证自己的想法是否可行,具体的实现需要做以下几个内容:

  • 准备定义两个重要属性,它们将会参与计算位置和绘制内容
  • radius:用于确定圆的半径
  • offset:用于表示圆点到item顶部的距离
  • 并且在getItemOffsets中留出绘制整个时间线的空间,即item的左边距
  • 最重要的工作内容是我们计算并绘制了圆和线(具体的计算可以看代码)
class FirstVerTimeline : RecyclerView.ItemDecoration() {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
var radius = 8f
var offset = 15
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) {
// 获取当前的itemView
val itemView = parent.getChildAt(i)
// 整个轴线的x坐标都是相同的
val xPosition = radius
// 画上线。第一个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())

android获取阴历的日期呢 安卓获取当前时间代码_android

已经初具规模了!只是时间线和文字之间挤了一点,我们只需要加上一些合适的padding,换一下测试数据,看起来就会像真的一样了!

android获取阴历的日期呢 安卓获取当前时间代码_ide_02

为了从图1到达图2,我们需要做:

  • 定义paddingLeftpaddingRight属性,用来表示轴线的左右padding
  • 修改getItemOffsetsoutRect.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) {