You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Jetpack Compose实现如图所示的时间线?

使用Jetpack Compose实现目标时间线的方案

针对你提供的时间线样式(垂直节点+连线+内容布局),以下是具体的实现思路和代码示例:

整体结构分析

目标时间线核心结构为:

  • 垂直贯穿的连线,区分已完成/未完成状态
  • 每个节点包含状态标记点、时间文本、内容卡片
  • 节点间通过连线衔接,首尾节点仅保留单侧连线

核心实现步骤

  1. 定义数据模型:封装时间线节点的时间、内容、完成状态
  2. 实现单个时间线项:通过Row拆分标记区、时间区、内容区,用Box绘制节点和连线
  3. 组合时间线容器:遍历数据列表,传递首尾节点的判断参数,处理连线显示逻辑

代码实现示例

1. 数据类定义

data class TimelineItem(
    val time: String,
    val title: String,
    val description: String,
    val isCompleted: Boolean
)

2. 单个时间线节点组件

@Composable
fun TimelineItem(item: TimelineItem, isFirst: Boolean, isLast: Boolean) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 16.dp, horizontal = 12.dp),
        verticalAlignment = Alignment.Top
    ) {
        // 标记区:包含节点和上下连线
        Box(
            modifier = Modifier.width(24.dp),
            contentAlignment = Alignment.Center
        ) {
            // 上方连线(非首节点显示)
            if (!isFirst) {
                Box(
                    modifier = Modifier
                        .height(16.dp)
                        .width(1.dp)
                        .background(if (item.isCompleted) Color(0xFF4CAF50) else Color.Gray)
                        .align(Alignment.Top)
                )
            }

            // 状态节点标记
            Box(
                modifier = Modifier
                    .size(12.dp)
                    .background(
                        color = if (item.isCompleted) Color(0xFF4CAF50) else Color.Transparent,
                        shape = CircleShape
                    )
                    .border(
                        width = 1.dp,
                        color = if (item.isCompleted) Color(0xFF4CAF50) else Color.Gray,
                        shape = CircleShape
                    )
            )

            // 下方连线(非尾节点显示)
            if (!isLast) {
                Box(
                    modifier = Modifier
                        .height(16.dp)
                        .width(1.dp)
                        .background(if (item.isCompleted) Color(0xFF4CAF50) else Color.Gray)
                        .align(Alignment.Bottom)
                )
            }
        }

        // 时间文本区
        Text(
            text = item.time,
            modifier = Modifier
                .width(80.dp)
                .padding(end = 12.dp),
            fontSize = 12.sp,
            color = Color.Gray
        )

        // 内容卡片区
        Column(modifier = Modifier.weight(1f)) {
            Text(
                text = item.title,
                fontWeight = FontWeight.Bold,
                fontSize = 16.sp
            )
            Text(
                text = item.description,
                fontSize = 14.sp,
                color = Color.Gray,
                modifier = Modifier.padding(top = 4.dp)
            )
        }
    }
}

3. 时间线容器组件

@Composable
fun Timeline(items: List<TimelineItem>) {
    Column(modifier = Modifier.fillMaxWidth()) {
        items.forEachIndexed { index, item ->
            TimelineItem(
                item = item,
                isFirst = index == 0,
                isLast = index == items.size - 1
            )
        }
    }
}

优化与扩展建议

  • 动态连线适配:如果内容高度不固定,可改用CustomLayout计算相邻节点的间距,让连线自动填充空隙,避免固定高度导致的错位
  • 状态动画:使用animateColorAsState实现完成状态切换时的颜色过渡动画,提升交互体验
  • 样式自定义:将节点颜色、大小、连线宽度等参数抽离为可配置参数,让组件适配更多场景
  • 响应式布局:在小屏设备上隐藏时间文本区,或改用垂直布局堆叠时间与内容

内容的提问来源于stack exchange,提问作者kururu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 03:00:22