写点什么

又来新需求了,急,Android 怎么实现时间线效果 (1),android 开发面试自我介绍

用户头像
Android架构
关注
发布于: 15 小时前
  • 然后我们自然可以注意到,在一个项的时间线中,又出现了两种颜色:圆上面的线(以下简称为上线)是绿色,圆本身圆下面的线(以下简称为下线)又是红色

  • 也就是说,这个 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())



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



为了从图 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<T> : RecyclerView.ItemDecoration() {


// 其他属性...


var data: List<T> = ArrayList() //-->这里有更新,定义了数据源


var color: (item: T) -> Int = { _ -> Color.GRAY } //-->这里有更新,通过这个属性设置颜色选择策略


override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.S


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


tate) {


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(...)


}

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
又来新需求了,急,Android怎么实现时间线效果(1),android开发面试自我介绍