又来新需求了,急,Android 怎么实现时间线效果,成体系化的神级 Android 进阶笔记
背景
==
这天下班前,老板找到小庄:有个页面要优化,小需求,你跟进一下。
小庄:好的老板! 他看了看时间,忐忑地翻出原型,看到了这样一个页面:
思索片刻后,小庄熟练地打开了某搜索引擎,没有找到合适的轮子,小庄知道软件开发的第一步必须是先进行需求分析和设计,而不是撸起袖子一把梭。于是他决定先分析下功能并整理思路。
预警:本文非常啰嗦,而且没有干货(害怕.jpg)
分析
==
功能分析
页面的大致功能:
该页面是个展示了某种流程的列表,每个列表项有不同的状态(已完成、进行中、未开始)
在列表的一侧有个类似时间线的 view,根据每个项的状态不同,展示不同颜色的圆点和竖线
细节分析
某一个项的时间线 view,其中有哪些细节呢?
首先发现,这个时间线 view 是由两个大部分组成的,分别是:圆、线
然后我们自然可以注意到,在一个项的时间线中,又出现了两种颜色:圆上面的线(以下简称为上线)是绿色,圆本身和圆下面的线(以下简称为下线)又是红色
也就是说,这个 view 不仅要知道自身的颜色,还得知道上一个 item 是什么颜色的
也就是说,这个 view 的绘制应该分成三个部分,分别是:上线、圆、下线
这是一个普通的中间的 item。然而对于第一个 item 和最后一个 item 来说,它们是分别没有上线和下线的
开始编码
====
小庄现在已经有了基本的思路和知识储备,他打开 IDE 准备动手编码了。不过软件开发是迭代的过程,即使是这样的一个小需求,他也打算先从实现一个简单的版本开始。
第一版
第一个版本,小庄打算只实现画出圆和线的形状,没有状态也没有颜色,主要为了验证自己的想法是否可行,具体的实现需要做以下几个内容:
准备定义两个重要属性,它们将会参与计算位置和绘制内容
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<Record>())// 省略构造假数据
rv_timeline1.addItemDecoration(FirstVerTimeline())
![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91c
GxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy8xMDk1OTAwLTdmYjAzZjc3OGIxNGI4NGQucG5n?x-oss-process=image/format,png)
已经初具规模了!只是时间线和文字之间挤了一点,我们只需要加上一些合适的 padding,换一下测试数据,看起来就会像真的一样了!
为了从图 1 到达图 2,我们需要做:
定义
paddingLeft
和paddingRight
属性,用来表示轴线的左右 padding修改
getItemOffsets
为outRect.left = paddingLeft + paddingRight + radius.toInt() * 2
,留出偏移量的位置修改
xPosition
的初始值为radius + paddingLeft
,改变轴线的 x 坐标
到这里第一个版本就算完成啦,第二个版本会有什么新功能呢
第二版
小庄打算在第二版里实现状态的不同颜色。为了实现这个需求,他陷入了深深的沉思:
数据类中肯定不可能耦合颜色这种 UI 实现,所以需要一个由状态获取颜色的办法
评论