Android

关注公众号 jb51net

关闭
首页 > 软件编程 > Android > Android实现时间线效果

Android如何实现时间线效果

作者:成活

这篇文章主要介绍了 Android如何实现时间线效果,下面文章围绕 Android如何实现时间线效果的相关资料展开详细内容,具有一定的参考价值 ,需要的朋友可以参考一下

1、背景

这天下班前,老板找到小庄:“有个页面要优化,小需求,你跟进一下。”
小庄:“好的老板!”他看了看时间,忐忑地翻出原型,看到了这样一个页面:

需要优化页面的原型图:

思索片刻后,小庄熟练地打开了某搜索引擎,没有找到合适的轮子,小庄知道软件开发的第一步必须是先进行需求分析和设计,而不是撸起袖子一把梭。于是他决定先分析下功能并整理思路。

2、分析

2.1功能分析

页面的大致功能:

2.2细节分析

对于其中一个项的时间线view,有哪些细节呢?

首先发现,这个时间线view是由两个大部分组成的,分别是:圆、线

然后我们自然可以注意到,在一个项的时间线中,又出现了两种颜色:圆上面的线(以下简称为上线)是绿色,圆本身和圆下面的线(以下简称为下线)又是红色

这是一个普通的中间的item。然而对于第一个item和最后一个item来说,它们是分别没有上线和下线的

2.3方案设想

小庄的脑海里迅速地闪过了几个想法:

第一个想法是根据数据的状态,在adapter中设置颜色和是否线显示。

第二个想法就是使用自定义view,在每一个item中画出圆和线,然后用自定义属性设置颜色。

也许是命中注定他将推开一扇大门:旁友,也许你听说过RecyclerView.ItemDecoration吗?

注:2000 years later,我发现我根本复现不出来那问题,也许这就是缘分吧

RecyclerView.ItemDecoration简介

这是一款功能强大的神器,用来给列表添加分隔线只是它最常见又最普通的能力。这里简单介绍一下,不是本文的主要内容。因为它能实现的效果太多太厉害了,我学不过来(ಥ_ಥ)

实现自定义的一个ItemDecoration,需要继承它并按需重写以下两个方法:

onDraw:用于具体的绘制内容

getItemOffsets:用于控制item的四周的偏移量,onDraw中绘制的内容会在这些留白上画出来

3、编码

小庄现在已经有了基本的思路和知识储备,他打开IDE准备动手编码了。不过软件开发是迭代的过程,即使是这样的一个小需求,他也打算先从实现一个简单的版本开始。

3.1第一版

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

具体的实现需要做以下几个内容:

准备定义两个重要属性,它们将会参与计算位置和绘制内容

并且在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,我们需要做:

定义paddingLeft和paddingRight属性,用来表示轴线的左右padding

到这里第一个版本就算完成啦,第二个版本会有什么新功能呢↓↓↓

3.2第二版

小庄打算在第二版里实现状态的不同颜色。为了实现这个需求,他陷入了深深的沉思:

函数类型是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.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...

}

代码中可能需要注意的点:

使用时也需要有一些变化:

val secondVerTimeline = SecondVerTimeline<Record>()

secondVerTimeline.data = records

secondVerTimeline.color = { item ->

    when (item.status) {

        1 -> color1

        2 -> color2

        ...

    }

}

rv_timeline2.addItemDecoration(secondVerTimeline)

然后就可以运行看一下效果了:

哇哦,鹅妹子嘤,这样就已经实现根据状态转变颜色的功能了!第二版的功能也圆满实现!

4、结语

后来小庄又根据UI一顿修修改改,很快就完成了这个需求~但是小庄是一个有追求的程序员,他开始思考起了这个代码的扩展性和通用性如何。不想不要紧,一想发现根本没有鸭!如果产品想要把圆点变成图片怎么办?或者产品想要更随风飞翔自由是方向呢?

于是他想找个时间完善改进一下这个ItemDecoration,最好能应对产品的所有需求!具体升级内容请看下集~

到此这篇关于 Android如何实现时间线效果的文章就介绍到这了,更多相关 Android实现时间线效果内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文