flutter---进度条

效果图

标准蓝色进度条

环形进度条和仪表盘进度条

标准蓝色进度条的实现步骤

1.设置变量

Dart 复制代码
double _sliderValue1 = 0.3;,//进度条默认滑动的距离的比例

2.设置进度条的通用子项

Dart 复制代码
 // ================= 标准蓝色进度条 =================
  Widget _buildSliderCard({
    required String title, //进度条标题
    required double value, //当前的进度值 (0.0~1.0)
    required ValueChanged<double> onChanged, //值改变时的回调函数
    required Color color, //进度条激活时的颜色
    bool showValue = false, //是否显示百分比
  }) {
    return Container(
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: const Color(0xFF1E293B),
        borderRadius: BorderRadius.circular(12),
        border: Border.all(color: Colors.white.withOpacity(0.1)),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              //标题
              Text(
                title,
                style: const TextStyle(
                  color: Colors.white,
                  fontSize: 14,
                  fontWeight: FontWeight.w500,
                ),
              ),

              //进度条滑动的值
              if (showValue)
                Text(
                  '${(value * 100).toInt()}%',//value*100转化为百分比,.toInt是取证的方法
                  style: const TextStyle(
                    color: Color(0xFF94A3B8),
                    fontSize: 12,
                  ),
                ),
            ],
          ),
          const SizedBox(height: 12),

          //进度条核心部分
          SliderTheme(
            data: SliderThemeData(
              trackHeight: 8, //进度条轨道高度
              thumbShape: const RoundSliderThumbShape(
                enabledThumbRadius: 10, //滑块半径
                pressedElevation: 18, //按下时阴影高度
              ),
              overlayShape: const RoundSliderOverlayShape(overlayRadius: 16), //点击涟漪效果半径
              activeTrackColor: color, //激活的颜色
              inactiveTrackColor: Colors.white.withOpacity(0.1),//未激活的颜色
              thumbColor: Colors.white, //滑块颜色
              overlayColor: color.withOpacity(0.2), //点击涟漪效果
            ),
            child: Slider(//自动检测和计算滑动的大小和方向
              value: value, //绑定当前值
              onChanged: onChanged, //绑定回调函数,当用户滑动时被调用
            ),
          ),
        ],
      ),
    );
  }

3.使用这个子项

Dart 复制代码
        _buildSliderCard(
            title: '标准蓝色进度条', //标题
            value: _sliderValue1, //进度条当前进度值
            onChanged: (newValueFromSlider) => setState(() => _sliderValue1 = newValueFromSlider),
            color: const Color(0xFF2178E3), //进度条激活颜色
            showValue: true, //是否显示百分比
          ),

完整代码执行逻辑

Dart 复制代码
1. 初始构建
_sliderValue1 = 0.3
Slider.value = 0.3
显示百分比: 30%

2. 用户滑动到35%位置
Slider检测到滑动 → 调用 onChanged(0.35),newValueFromSlider = 0.35 

3. 执行回调
setState(() => _sliderValue1 = 0.35)
_sliderValue1 更新为 0.35

4. 触发重新构建
build() 方法再次执行

5. 传递新值给组件
_buildSliderCard(value: 0.35, ...)

6. 组件内部
- Slider.value = 0.35
- 滑块移动到35%位置
- 文字更新: '35%'

7. UI更新完成
环形进度条和仪表盘进度条的实现步骤

1.设置变量,初始进度条值

Dart 复制代码
double _sliderValue2 = 0.3;

2.设置环形进度条的UI框架的通用子项

Dart 复制代码
  Widget _buildCircularProgressCard({
    required String title, //标题
    required double value, //当前进度值
    required ValueChanged<double> onChanged, //值变化的回调
  }) {
    return Container(
      width: 150,
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: const Color(0xFF1E293B),
        borderRadius: BorderRadius.circular(12),
        border: Border.all(color: Colors.white.withOpacity(0.1)),
      ),
      child: Column(
        children: [
          //标题
          Text(
            title,
            style: const TextStyle(
              color: Colors.white,
              fontSize: 14,
              fontWeight: FontWeight.w500,
            ),
          ),
          const SizedBox(height: 12),
          SizedBox(
            height: 100,
            child: Stack(
              alignment: Alignment.center, //所有子项居中对齐,所以背景圆环和进度圆环能自定对齐圆心
              children: [

                // 背景圆环
                Container(
                  width: 88,
                  height: 88,
                  decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    border: Border.all(
                      color: Colors.white.withOpacity(0.1),
                      width: 8, //边框宽度:这个边框宽度做了圆形进度条的背景
                    ),
                  ),
                ),

                // 进度圆环
                SizedBox(
                  width: 80,
                  height: 80,
                  child: CircularProgressIndicator( //绘制环形进度条
                    value: value, //传入值
                    strokeWidth: 8, //传入圆环的粗细
                    backgroundColor: Colors.transparent,
                    valueColor: AlwaysStoppedAnimation( //传入进度条激活的颜色
                      Color(0xFF3B82F6).withOpacity(0.7),
                    ),
                  ),
                ),


                // 中心文本
                Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text(
                      '${(value * 100).toInt()}%',
                      style: const TextStyle(
                        color: Colors.white,
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    Text(
                      '进度',
                      style: TextStyle(
                        color: Colors.white.withOpacity(0.6),
                        fontSize: 10,
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
          const SizedBox(height: 8),

          //控制滑块
          SizedBox(
            height: 20, //滑块区域高度
            child: Slider(
              value: value,
              onChanged: onChanged, //值变化时回调
              activeColor: const Color(0xFF3B82F6), //激活颜色
              inactiveColor: Colors.white.withOpacity(0.1), //未激活颜色
            ),
          ),
        ],
      ),
    );
  }

3.设置仪表盘进度条的UI框架

Dart 复制代码
  Widget _buildGaugeProgressCard({
    required String title, //标题
    required double value, //当前进度值
    required ValueChanged<double> onChanged, //值变化回调
  }) {
    return Container(
      width: 150,
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: const Color(0xFF1E293B),
        borderRadius: BorderRadius.circular(12),
        border: Border.all(color: Colors.white.withOpacity(0.1)),
      ),
      child: Column(
        children: [
          //标题
          Text(
            title,
            style: const TextStyle(
              color: Colors.white,
              fontSize: 14,
              fontWeight: FontWeight.w500,
            ),
          ),
          const SizedBox(height: 12),

          //仪表盘绘制区域
          SizedBox(
            height: 60,
            child: CustomPaint(
              size: const Size(100, 60), //绘制区域
              painter: _GaugePainter(value: value),//自定义绘制器
            ),
          ),
          const SizedBox(height: 48),

          //控制滑块
          SizedBox(
            height: 20,
            child: Slider(
              value: value,
              onChanged: onChanged,
              activeColor: const Color(0xFF1D4ED8),
              inactiveColor: Colors.white.withOpacity(0.1),
            ),
          ),
        ],
      ),
    );
  }

4.绘制仪表盘进度条

Dart 复制代码
class _GaugePainter extends CustomPainter {

  final double value; //进度值(0.0~1.0)

  _GaugePainter({required this.value}); //构造函数,接收进度值

  @override
  void paint(Canvas canvas, Size size) {
    const startAngle = -pi * 1.3; //起始角度
    const sweepAngle = pi * 1.6;  //总角度范围
    final center = Offset(size.width / 2, size.height * 0.8); //圆心位置
    const radius = 40.0; //圆弧半径

    // 绘制背景圆弧
    final backgroundPaint = Paint() //创建画笔
      ..color = Colors.white.withOpacity(0.1) //背景颜色
      ..style = PaintingStyle.stroke //描边模式
      ..strokeWidth = 8  //线条宽度
      ..strokeCap = StrokeCap.round; //线条端点圆角

    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius), //圆弧所在矩形
      startAngle, //使用起始角度
      sweepAngle, //使用角度范围
      false, //不填充中心,只是描边
      backgroundPaint, //使用画笔
    );

    // 绘制进度圆弧
    final progressPaint = Paint() //绘制画笔
      ..color = const Color(0xFF1D4ED8) //背景颜色
      ..style = PaintingStyle.stroke //描边模式
      ..strokeWidth = 8 //线宽
      ..strokeCap = StrokeCap.round; //线条端点圆角

    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      startAngle,
      sweepAngle * value,
      false,
      progressPaint,
    );

    //绘制指针
    //指针角度 = 起始角度 + (总角度 * 进度值)
    final pointerAngle = startAngle + sweepAngle * value;
    final pointerPaint = Paint()
      ..color = Colors.white
      ..style = PaintingStyle.fill; //填充模式

    //绘制指针圆点
    canvas.drawCircle(
      center, //圆心位置
      6, //半径
      pointerPaint,
    );

    // 绘制指针线
    final pointerLinePaint = Paint()
      ..color = Colors.white
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2;

    //计算指针终点位置
    final pointerEnd = Offset( //计算
      center.dx + cos(pointerAngle) * radius * 0.8, //X坐标
      center.dy + sin(pointerAngle) * radius * 0.8, //Y坐标
    );

    //绘制从圆心到终点的线条
    canvas.drawLine(center, pointerEnd, pointerLinePaint);

    // 绘制刻度值
    final textPainter = TextPainter(
      text: TextSpan(
        text: '${(value * 100).toInt()}', //计算百分比
        style: const TextStyle(
          color: Colors.white,
          fontSize: 20,
          fontWeight: FontWeight.bold,
        ),
      ),
      textDirection: TextDirection.ltr, //从左到右文本方向
    );

    textPainter.layout(); //布局计算文本尺寸
    textPainter.paint(
      canvas,
      Offset( //位置
          center.dx - textPainter.width / 2,  //水平居中
          center.dy - 40 //圆心上方的位置
      ),
    );

    // 绘制百分号单位
    final unitPainter = TextPainter(
      text: const TextSpan(
        text: '%',
        style: TextStyle(
          color: Colors.white70,
          fontSize: 12,
        ),
      ),
      textDirection: TextDirection.ltr,
    );

    unitPainter.layout();
    unitPainter.paint(
      canvas,
      Offset(center.dx - unitPainter.width / 2, center.dy - 15), //位置
    );
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

5.使用这两个进度条

Dart 复制代码
// 环形和仪表盘进度条
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              //环形进度条
              _buildCircularProgressCard(
                title: '环形进度条',
                value: _sliderValue2,
                onChanged: (value) => setState(() => _sliderValue2 = value),
              ),

              //仪表盘进度条
              _buildGaugeProgressCard(
                title: '仪表盘进度条',
                value: _sliderValue2,
                onChanged: (value) => setState(() => _sliderValue2 = value),
              ),
            ],
          ),
相关推荐
sunly_42 分钟前
Flutter:布局:NestedScrollView+SliverAppBar+SmartRefresher(分页),实现顶部背景图+导航栏渐变+分页列表
flutter
阿桂有点桂1 小时前
Flutter使用VS Code打包app
vscode·flutter·安卓
时间的情敌1 小时前
Vue3 和 Vue2 的核心区别
前端·javascript·vue.js
533_1 小时前
[antv x6] 限制节点/边是否可以移动,移动时返回父节点,限制节点的移动范围
前端
步步为营DotNet1 小时前
深入理解ASP.NET Core Middleware:构建高效Web应用的管道基石
前端·后端·asp.net
Aevget1 小时前
DevExtreme JS & ASP.NET Core v25.2新功能预览 - 提升AI扩展功能
javascript·人工智能·ui·asp.net·界面控件·devextreme
|晴 天|1 小时前
微前端架构入门:从概念到落地实践
前端·架构
春卷同学1 小时前
电子蛇对战 - Electron for 鸿蒙PC项目实战案例
javascript·electron·harmonyos