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

如何基于已有数据创建Flutter填充式进度条容器

实现带进度背景的列表组件

首先先把你的数据结构小问题修正下,原来的programStepCounts初始化写错了,得用StepProgress的构造函数创建实例,不然跑不起来:

final Map<ProgressKeys, StepProgress> programStepCounts = {
  ProgressKeys.articles: StepProgress(
    displayText: "Articles Read",
    progress: 2,
    count: 4,
  ),
  ProgressKeys.meals: StepProgress(
    displayText: "Meals Logged",
    progress: 3,
    count: 9,
  ),
  // 其他项照着补就行
};

接下来实现核心的进度列表项,咱们用Stack来叠背景和文字,这样就能做出左边填充颜色的效果。直接上代码:

// 单个进度项组件
class ProgressListItem extends StatelessWidget {
  final StepProgress progress;

  const ProgressListItem({super.key, required this.progress});

  @override
  Widget build(BuildContext context) {
    // 算一下进度占比,比如2/4就是0.5,用来控制背景宽度
    final progressRatio = progress.progress / progress.count;

    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      child: Container(
        height: 60,
        // 外层灰色背景+圆角
        decoration: BoxDecoration(
          color: Colors.grey[200],
          borderRadius: BorderRadius.circular(8),
        ),
        child: Stack(
          children: [
            // 进度填充的蓝色背景
            ClipRRect(
              borderRadius: BorderRadius.circular(8),
              // 宽度按比例来,减去左右的padding,刚好填满外层容器的有效宽度
              child: Container(
                width: (MediaQuery.of(context).size.width - 32) * progressRatio,
                color: Colors.blue[300],
              ),
            ),
            // 上面叠文字和进度数字
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(
                    progress.displayText,
                    style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
                  ),
                  Text(
                    "${progress.progress}/${progress.count}",
                    style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

最后用你想到的ListView.builder把所有项渲染出来:

class ProgressScreen extends StatelessWidget {
  const ProgressScreen({super.key});

  @override
  Widget build(BuildContext context) {
    // 把Map里的值转成列表,方便ListView遍历
    final progressItems = programStepCounts.values.toList();

    return Scaffold(
      appBar: AppBar(title: const Text("进度追踪")),
      body: ListView.builder(
        itemCount: progressItems.length,
        itemBuilder: (context, index) {
          return ProgressListItem(progress: progressItems[index]);
        },
      ),
    );
  }
}

关键说明

  • Stack就是用来把多个组件叠在一起的,背景在底下,文字在上面,刚好符合需求。
  • ClipRRect是为了让蓝色的进度背景和外层灰色容器的圆角保持一致,不然会露出直角,影响美观。
  • 进度比例计算很简单,已完成数除以总数,得到的比例用来控制背景宽度,就能实现随进度变化的填充效果。

你可以自己改颜色、圆角大小、容器高度这些参数,调成你想要的样子。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 06:45:35