如何不使用第三方库实现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
相关产品推荐
相关产品推荐

