如何在Flutter中创建双向延伸的投票进度条?
Flutter 双向投票进度条实现方案
直接用Flutter原生组件就能实现这个效果,核心思路是用Stack叠加左右两个进度条,根据投票数动态计算各自的宽度。下面是完整的可运行代码:
import 'package:flutter/material.dart'; class BidirectionalVoteBar extends StatefulWidget { const BidirectionalVoteBar({super.key}); @override State<BidirectionalVoteBar> createState() => _BidirectionalVoteBarState(); } class _BidirectionalVoteBarState extends State<BidirectionalVoteBar> { int yesCount = 0; int noCount = 0; // 计算投票比例 double get _yesRatio { final total = yesCount + noCount; return total == 0 ? 0 : yesCount / total; } double get _noRatio { final total = yesCount + noCount; return total == 0 ? 0 : noCount / total; } @override Widget build(BuildContext context) { final barWidth = MediaQuery.of(context).size.width * 0.8; final barHeight = 40.0; return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 投票进度条区域 Stack( alignment: Alignment.center, children: [ // 背景条 Container( width: barWidth, height: barHeight, decoration: BoxDecoration( color: Colors.grey[200], borderRadius: BorderRadius.circular(20), ), ), // YES 进度条(从左延伸) Align( alignment: Alignment.centerLeft, child: Container( width: barWidth * _yesRatio, height: barHeight, decoration: const BoxDecoration( color: Colors.green, borderRadius: BorderRadius.only( topLeft: Radius.circular(20), bottomLeft: Radius.circular(20), ), ), ), ), // NO 进度条(从右延伸) Align( alignment: Alignment.centerRight, child: Container( width: barWidth * _noRatio, height: barHeight, decoration: const BoxDecoration( color: Colors.red, borderRadius: BorderRadius.only( topRight: Radius.circular(20), bottomRight: Radius.circular(20), ), ), ), ), // 中间显示总票数 Text( '${yesCount + noCount}', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white, ), ), ], ), const SizedBox(height: 20), // 投票按钮 Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.green), onPressed: () => setState(() => yesCount++), child: const Text('YES'), ), const SizedBox(width: 20), ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.red), onPressed: () => setState(() => noCount++), child: const Text('NO'), ), ], ), ], ); } } // 测试用的主页面 void main() { runApp(const MaterialApp( home: Scaffold( body: Center(child: BidirectionalVoteBar()), ), )); }
关键实现细节:
- 用
Stack将背景条、YES进度条、NO进度条叠加,YES进度条左对齐,NO进度条右对齐 - 通过
_yesRatio和_noRatio动态计算两个进度条的宽度,确保比例正确 - 进度条和背景条都做了圆角处理,贴合示例效果
- 点击按钮更新票数后,调用
setState刷新UI,自动更新进度条宽度
你可以根据需求调整:
- 修改进度条的高度、圆角大小、颜色
- 调整按钮样式或添加更多交互逻辑
- 把票数存储到状态管理工具(比如Provider、Riverpod)中,实现跨页面状态同步
内容的提问来源于stack exchange,提问作者Leo
相关产品推荐
相关产品推荐

