时间轴、流程类时间轴绘制

效果图

  • 可控制是否绘制在中间
  • 控制绘制的线条是否为虚线
  • 控制第一条数据圆顶部线条和最后一条数据圆底部线条是否绘制

除了gif图片展示的属性,还可以控制圆的大小颜色、圆是否有上和左偏移、线条颜色等属性

除了通用的时间轴绘制,我们还可以通过改变绘制圆的样式,改为绘制相应的bitmap图像,来实现展示相关的流程

思路

关于ItemDecoration相关的内容已经写了不少,这个其实就是小菜一碟。我们需要做的工作有两点

  • ItemDecoration在getItemOffsets()方法内做相应的偏移
  • onDraw()方法内分别绘制圆、圆顶部线条、圆底部线条
    • 绘制线条,我们需要知道start和end的点坐标;
    • 绘制圆,我们需要知道圆心和半径;

通过下图,你将能清楚地获取到这些绘制需要的一些信息

具体实现

有了以上内容,我们开始绘制

步骤一:ItemView顶部偏移

kotlin 复制代码
 override fun getItemOffsets(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State,
    ) {
        if (parent.getChildAdapterPosition(view) != 0) {
            //第一个不做顶部偏移
            outRect.top = topItemSpace
        }
        outRect.left = leftItemSpace

    }

步骤二:绘制圆和线条

kotlin 复制代码
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        //获取到的是当前屏幕可见的个数
        val childCount = parent.childCount

        for (i in 0 until childCount) {
            val view = parent.getChildAt(i)
            //获取真实的在整体数据中的位置
            val index=parent.getChildAdapterPosition(view)

            //ItemView左侧+偏移的矩形框(绿色框部分)
            val spaceRectTop = if (index == 0) view.top else view.top - topItemSpace
            val spaceRectBottom = view.bottom
            val spaceRectLeft = view.left - leftItemSpace
            val spaceRectRight = view.left

            //ItemView左侧,不包含偏移的矩形框(红色框部分)
            val dataRectLeft = view.left - leftItemSpace
            val dataRectTop = view.top
            val dataRectRight = view.left
            val dataRectBottom = view.bottom

            //圆心坐标
            var centerX = if(isDrawAtMiddle) (dataRectLeft + dataRectRight)/ 2  else (dataRectLeft + dataRectRight)/ 2 + circleLeftPadding
            val centerY =
                if (isDrawAtMiddle) (dataRectTop + dataRectBottom) / 2 else dataRectTop + circleRadius + circleTopPadding

            //绘制第一条线
            if (index==0){
                if (isDrawFirstItemTopLine){
                    c.drawLine(
                        centerX.toFloat(),
                        spaceRectTop.toFloat(),
                        centerX.toFloat(),
                        (centerY - circleRadius).toFloat(),
                        mLinePaint
                    )
                }
            }else{
                c.drawLine(
                    centerX.toFloat(),
                    spaceRectTop.toFloat(),
                    centerX.toFloat(),
                    (centerY - circleRadius).toFloat(),
                    mLinePaint
                )
            }
            //绘制圆(居中显示)
            c.drawCircle(centerX.toFloat(), centerY.toFloat(), circleRadius.toFloat(), mCirclePaint)


            //绘制第二条线,注意这里要用itemCount,因为上面的childCount是当前页面可见的个数
            parent.adapter?.let {
                if (index!=it.itemCount-1){
                    c.drawLine(
                        centerX.toFloat(),
                        (centerY + circleRadius).toFloat(),
                        centerX.toFloat(),
                        spaceRectBottom.toFloat(),
                        mLinePaint
                    )
                }else{
                    if (isDrawLastItemBottomLine){
                        c.drawLine(
                            centerX.toFloat(),
                            (centerY + circleRadius).toFloat(),
                            centerX.toFloat(),
                            spaceRectBottom.toFloat(),
                            mLinePaint
                        )
                    }
                }
            }
        }
    }

注意:下标的获取

因为我们需要每个ItemView都绘制,所以需要使用循环。但因为val childCount = parent.childCount获取到的是当前页面可见的个数,并不是实际的个数,所以我们在判断是否是首条或者最后一条数据时,那个index要通过val index=parent.getChildAdapterPosition(view)的方式来获取到真实的下标位置。

流程类的绘制

和绘制通用的圆类似,不过是将Canvas.drawCircle()改为Canvas.drawBitmap()。至于不同的bitmap的加载,我们可以通过传入集合的数据类型来判断绘制哪种图片即可。

kotlin 复制代码
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
	...
	val srcRect = Rect(0, 0, progressBitmap.width, progressBitmap.height)
	val dstRect = Rect(
        centerX - circleRadius,
        centerY - circleRadius,
        centerX + circleRadius,
        centerY + circleRadius
    )
    c.drawBitmap(errorBitmap, srcRect, dstRect, mCirclePaint)
    ...
}

总结

其实主要还是ItemDecoration相关的内容,在onDraw()方法内绘制圆、绘制bitmap和绘制线条,根据上面的图,知道具体的坐标位置,绘制就很轻松了,也可以在此基础上继续扩展,使得我们的时间轴ItemDecoration更加的通用,方便运用到项目中。

如果本文对你有帮助,请别忘记三连,如果有不恰当的地方也请提出来,下篇文章见。

相关推荐
林胖子的私生活21 小时前
绘制K线第五章:双指放大缩小
android
2501_9371892321 小时前
IPTV 2026 优化版:解码适配 + 安全运维双升级,筑牢使用体验基石
android·源码·开源软件·源代码管理
朽木成才1 天前
Android+Flutter混合开发实战
android·flutter
天燹1 天前
Qt 6 嵌入 Android 原生应用完整教程
android·开发语言·qt
美狐美颜sdk1 天前
企业级直播美颜SDK与动态贴纸SDK开发技术方案拆解与落地实践
android·人工智能·计算机视觉·第三方美颜sdk·人脸美型sdk
PwnGuo1 天前
Android逆向:在 Unidbg 中解决 native 函数内调用 Java 方法的报错
android·java·python
Kratzdisteln1 天前
【1902】优化后的三路径学习系统
android·学习
Digitally1 天前
如何将文件从 iPhone 传输到 Android
android·ios·iphone
a3158238061 天前
Android修改调试屏幕的选择方向
android·adb·屏幕旋转
超级数据查看器1 天前
超级数据查看器 更新日志(包含的功能)
android·java·数据库·sqlite·安卓