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

如何不使用第三方库实现Flutter时间线UI?求简易示例

无第三方库实现Flutter时间线布局

以下是完全基于Flutter原生组件实现的简易时间线布局,无需依赖任何第三方包,效果和你参考的布局一致:

1. 定义数据模型

先创建一个数据类来存储时间线项的核心信息:

class TimelineItem {
  final String title;
  final String subtitle;
  final bool isFirst;
  final bool isLast;

  TimelineItem({
    required this.title,
    required this.subtitle,
    required this.isFirst,
    required this.isLast,
  });
}

2. 实现主页面

用ListView.builder加载动态时间线列表,保证性能:

class TimelinePage extends StatelessWidget {
  final List<TimelineItem> items = [
    TimelineItem(
      title: "订单创建",
      subtitle: "2024-05-20 14:30",
      isFirst: true,
      isLast: false,
    ),
    TimelineItem(
      title: "支付完成",
      subtitle: "2024-05-20 14:35",
      isFirst: false,
      isLast: false,
    ),
    TimelineItem(
      title: "商家接单",
      subtitle: "2024-05-20 14:40",
      isFirst: false,
      isLast: false,
    ),
    TimelineItem(
      title: "配送中",
      subtitle: "2024-05-20 15:00",
      isFirst: false,
      isLast: false,
    ),
    TimelineItem(
      title: "已送达",
      subtitle: "2024-05-20 15:30",
      isFirst: false,
      isLast: true,
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("时间线示例")),
      body: ListView.builder(
        padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24),
        itemCount: items.length,
        itemBuilder: (context, index) {
          return TimelineItemWidget(item: items[index]);
        },
      ),
    );
  }
}

3. 实现单个时间线项组件

核心布局逻辑在这里,通过原生组件组合节点、连线和内容卡片:

class TimelineItemWidget extends StatelessWidget {
  final TimelineItem item;

  const TimelineItemWidget({super.key, required this.item});

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 32),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // 左侧时间线节点与连线
          SizedBox(
            width: 40,
            child: Column(
              children: [
                // 上方连线(仅非第一项显示)
                if (!item.isFirst)
                  Container(
                    width: 2,
                    height: 24,
                    color: Colors.grey.shade300,
                  ),
                // 状态节点
                Container(
                  width: 20,
                  height: 20,
                  decoration: BoxDecoration(
                    color: item.title == "已送达" ? Colors.green : Colors.blue,
                    borderRadius: BorderRadius.circular(10),
                  ),
                  child: item.title == "已送达"
                      ? const Icon(Icons.check, color: Colors.white, size: 12)
                      : null,
                ),
                // 下方连线(仅非最后一项显示)
                if (!item.isLast)
                  Container(
                    width: 2,
                    height: double.infinity,
                    color: Colors.grey.shade300,
                  ),
              ],
            ),
          ),
          // 右侧内容卡片
          Expanded(
            child: Container(
              padding: const EdgeInsets.all(16),
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(8),
                boxShadow: [
                  BoxShadow(
                    color: Colors.grey.shade200,
                    blurRadius: 4,
                    offset: const Offset(0, 2),
                  ),
                ],
              ),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    item.title,
                    style: const TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                  const SizedBox(height: 8),
                  Text(
                    item.subtitle,
                    style: TextStyle(
                      fontSize: 14,
                      color: Colors.grey.shade600,
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

关键细节说明

  • 用isFirst和isLast控制连线显示,避免首尾项出现多余线条
  • 通过颜色和图标区分已完成状态的节点,和参考布局视觉一致
  • 内容卡片添加阴影效果增强层次感,符合常见UI设计规范
  • 所有组件均为Flutter原生组件,无任何第三方依赖

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 15:10:19