如何在Flutter中实现Dribbble上的连接式列表UI效果?
Flutter实现连接式列表样式方案
要实现你提到的这种带竖线连接的列表效果,核心是给每个列表项添加左侧的装饰元素(竖线+圆点),并根据列表项的位置调整线条显示逻辑。以下是具体实现方式:
核心思路
每个列表项左侧通过Column组合绘制圆点和竖线,根据项的位置区分显示逻辑:
- 首项:仅显示下半段竖线+圆点
- 中间项:显示上下两段竖线+圆点
- 尾项:仅显示上半段竖线+圆点
代码实现
1. 自定义列表项组件
class ConnectedListItem extends StatelessWidget { final String title; final String subtitle; final double amount; final bool isFirst; final bool isLast; const ConnectedListItem({ super.key, required this.title, required this.subtitle, required this.amount, required this.isFirst, required this.isLast, }); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Row( children: [ // 左侧连接装饰 _buildConnectionDecor(), const SizedBox(width: 16), // 右侧内容区 Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 4), Text(subtitle, style: Theme.of(context).textTheme.bodySmall?.copyWith(color: Colors.grey)), ], ), ), Text( amount >= 0 ? "+${amount.toStringAsFixed(2)}" : amount.toStringAsFixed(2), style: Theme.of(context).textTheme.titleMedium?.copyWith( color: amount >= 0 ? Colors.green : Colors.red, ), ), ], ), ); } Widget _buildConnectionDecor() { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 上半段竖线,首项隐藏 if (!isFirst) Container(width: 2, height: 20, color: Colors.grey.shade300), // 圆点 Container( width: 12, height: 12, decoration: BoxDecoration(color: Colors.blue, borderRadius: BorderRadius.circular(6)), ), // 下半段竖线,尾项隐藏 if (!isLast) Container(width: 2, height: 20, color: Colors.grey.shade300), ], ); } }
2. 构建完整列表
class ConnectedListPage extends StatelessWidget { final List<Map<String, dynamic>> transactions = [ {"title": "Grocery Store", "subtitle": "Shopping", "amount": -45.20}, {"title": "Salary", "subtitle": "Monthly Payment", "amount": 2500.00}, {"title": "Subscription", "subtitle": "Streaming Service", "amount": -12.99}, {"title": "Freelance Work", "subtitle": "Project Payment", "amount": 800.00}, ]; ConnectedListPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("Transactions")), body: ListView.builder( itemCount: transactions.length, itemBuilder: (context, index) { final item = transactions[index]; return ConnectedListItem( title: item["title"], subtitle: item["subtitle"], amount: item["amount"], isFirst: index == 0, isLast: index == transactions.length - 1, ); }, ), ); } }
样式自定义说明
- 修改
_buildConnectionDecor里的容器颜色、大小,可适配你的设计风格 - 若需交互效果,可在
ConnectedListItem外层包裹InkWell组件 - 要添加动画,可将静态容器替换为
AnimatedContainer
内容的提问来源于stack exchange,提问作者Konstantinos Rotsidis
相关产品推荐
相关产品推荐

