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

效果图

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

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

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

流程类时间轴效果图

思路

关于ItemDecoration相关的内容已经写了不少,如果看过以前的文章自定义ItemDecoration分割线的高度、颜色、偏移,看完这个你就懂了、Android购物车效果实现(RecyclerView悬浮头部实现)

这个其实就是小菜一碟。我们需要做的工作有两点

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

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

在这里插入图片描述

具体实现

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

步骤一:ItemView顶部偏移

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

    }

步骤二:绘制圆和线条

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的加载,我们可以通过传入集合的数据类型来判断绘制哪种图片即可。

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更加的通用,方便运用到项目中。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/701774.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

国外创意二维码应用:飞利浦旧物翻新活动,传播可持续性消费的重要性!

你知道去年有超过1000万件礼物被扔进了垃圾场吗? 这些被丢弃的物品中有许多仍在使用,飞利浦希望改变这种浪费现象。 去年的地球日,飞利浦策划了一场名为“Better than New” 的二维码营销活动。他们发布了一个视频,通过这个短视频将所有最终…

微信小程序组件传值

虽然微信小程序是比较轻量的,但是还是拥有组件的 这是文件的基本目录 我们的代码基本都在pages和components文件夹中 在component中创建组件 在component中 ,创建一个目录 我创建了一个 head目录 用于配置头部信息 我在这里创建了 一个头部组件&…

Vue基础知识:异步DOM更新是什么?$nextTick是什么?到底应该如何使用。什么是同步?什么是异步?

要先了解异步dom更新是什么就必须先了解,什么是同步?什么是异步? 1.什么是同步?什么是异步? 同步(Synchronous): 同步操作是按照代码的顺序执行的,每个操作都必须等待上…

NiceGUI:让Python变身为Web应用开发大师的神器

简介 NiceGUI是一个易于使用的基于Python的UI框架,可以在您的Web浏览器中使用。您可以创建按钮、对话框、Markdown、3D场景、图表等等。 NiceGUI开源支持较好,代码更新频率较高,目前已经更新至: V1.4.26。 适用场景 NiceGUI非常适用于各种…

为什么 JavaScript 在国外逐渐用于前端+后端开发

这个问题其实没人能给出可证伪的结论,那不如干脆给一个感性的答案: 因为阿里“不争气”。 确切的说,因为阿里的nodejs团队没卷赢,至少暂时还没卷赢,没拿到真正有价值的业务场景,做出真正有说服力的案例项目。刚好我有…

【微信小程序】开发环境配置

目录 小程序的标准开发模式: 注册小程序的开发账号 安装开发者工具 下载 设置外观和代理 第一个小程序 -- 创建小程序项目 查看项目效果 第一种:在模拟器上查看项目效果 项目的基本组成结构 小程序代码的构成 app.json文件 project.config…

8.2 Go 导入与导出

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

手机短信验证码登录

用户需求: 1、用户使用手机号和短信验证码登录系统 2、未注册过的手机号再登录时实现自动注册 3、新注册的账号只有7天的使用时间,过期后不允许进行登录 功能需求: 登录页面设计 图1.手机号登录 【验证码登录】规则说明: …

各类电机数学模型相关公式总结 —— 集成芯片驱动

0、背景技术概述 永磁直流电机(PMDC)、永磁同步电机(PMSM)、无刷直流电机(BLDC)以及混合式两相步进电机在小功率应用场景中多采用集成芯片驱动(如二合一、三合一驱动芯片)的原因主要…

Linux C语言:函数的基本用法及传参

一、函数的基本用法 1、main函数 int main(int argc, const char * argv[]) { printf("Hello world\n"); return 0; }数据类型 函数名称 (参数) { //.... return 表达式 } 2、函数 函数是一个完成特定功能的代码模块,其程序代码独立,通常要…

使用Python修改word文档中的表格

使用Python编辑word文档中的表格 介绍效果代码代码解析 介绍 使用python修改word文档中的表格。 效果 修改前的word文档: 注意红框中的表格。 修改后的word文档: 表格内容已经修改。 代码 from docx import Document# 加载现有的Word文档 doc D…

electron基础使用

安装以及运行 当前node版本18,按照官网提供操作,npm init进行初始化操作,将index.js修改为main.js,执行npm install --save-dev electron。(这里我挂梯子下载成功了。),添加如下代码至package.…

AI办公自动化:用Kimi批量在Excel文件名中加入日期

工作任务:在一个文件夹中所有的Excel文件后面加上一个日期 在Kimi中输入提示词: 你是一个Python编程专家,写一个Python脚本,具体步骤如下: 打开文件夹:F:\AI自媒体内容\AI行业数据分析\投融资 读取里面所…

电商核心技术系列58:电商平台的智能数据分析与业务洞察

相关系列文章 电商技术揭秘相关系列文章合集(1) 电商技术揭秘相关系列文章合集(2) 电商技术揭秘相关系列文章合集(3) 电商核心技术揭秘56:客户关系管理与忠诚度提升 电商核心技术揭秘57:数…

Codeforces Round 951 (Div. 2) A~E

A.Guess the Maximum(枚举) 题意: 爱丽丝和鲍勃想出了一个相当奇怪的游戏。他们有一个整数数组 a 1 , a 2 , … , a n a_1,a_2,\ldots,a_n a1​,a2​,…,an​。爱丽丝选择了某个整数 k k k并告诉了鲍勃,然后就发生了下面的事情&…

UiPath发送邮件给多人时需要注意哪些限制?

UiPath发送邮件给多人的步骤?如何使用UiPath发信? 尽管UiPath提供了强大的邮件发送功能,但在批量发送邮件时,有一些限制和注意事项是我们必须了解的。AokSend将详细介绍这些限制,并提供一些优化建议。 UiPath发送邮件…

ArrayList和LinkedList的区别!!!

总结: 1、数据结构的实现 ArrayList:动态数组。 LinkedList:双向链表。 2、时间复杂度不同 ArrayList:O(1) LinkedList: O(n) ①:随机访问---- ArrayList > LinkedList (ArrayList采用下标&#xff0…

frps 0.33

一个模拟示例 下载windows版本的frfps 需要准备的测试设备 一台frp服务器一台frp客户端PCsscom5.exe测试软件开2个,来模拟野外的设备和本地连接野外设备的软件。原理 frp服务器搭建了一条中转的桥梁,frp的客户端在本地做好端口映射后,本地的设备软件就可以连接到野外的设…

第34章-WLAN

1. 概述 2. WLAN模式 3. 相关概念 1. 概述 ① 定义WLAN(Wireless Local Area Network,无线局域网),是一种技术; ② WLAN技术: Wi-Fi WAPI:中国强制标准; 例子:苹果手机 -- 设置 -- 国行(无线局域网设置) …

大众点评全国学习培训POI采集99万家-2024年5月底

大众点评全国学习培训POI采集99万家-2024年5月底 店铺POI点位示例: 店铺id k40VtNBN3bixFJIU 店铺名称 梦想钢琴成人钢琴(珠江新城总部) 十分制服务评分 9.4 十分制环境评分 9.4 十分制划算评分 9.4 人均价格 80 评价数量 6705 店铺地址 华穗路263号双城国…