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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 19:05:32