import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; /// ============================================================ /// 背诵模块进度条组件 /// /// 1. GradientProgressBar —— 对标 Vue r-progress(linear-gradient 填充) /// 词书卡蓝色渐变 / 关卡绿色渐变 / 未解锁灰色,全靠 colors 切换。 /// /// 2. SegmentedProgressBar —— 对标 Vue SegmentedProgressBar.vue /// 三段独立进度,每段各自按 33/33/34 比例填充,绿色渐变。 /// ============================================================ /// 渐变线性进度条(percent:0~100) class GradientProgressBar extends StatelessWidget { const GradientProgressBar({ super.key, required this.percent, this.height = 6, this.colors = const [Color(0xFF84AFFF), Color(0xFF3C7CF6)], this.trackColor = const Color(0xFFF5F5F5), this.radius, }); /// 0~100(自动 clamp) final double percent; final double height; /// 填充渐变(单色时传同色两个即可) final List colors; final Color trackColor; final double? radius; @override Widget build(BuildContext context) { final safe = percent.clamp(0, 100).toDouble(); return ClipRRect( borderRadius: BorderRadius.circular(radius ?? (height / 2).r), child: LayoutBuilder( builder: (context, constraints) { final width = constraints.maxWidth; return Container( height: height.w, color: trackColor, child: Align( alignment: Alignment.centerLeft, child: SizedBox( width: width * safe / 100, child: DecoratedBox( decoration: BoxDecoration( gradient: LinearGradient( colors: colors, begin: Alignment.centerLeft, end: Alignment.centerRight, ), ), ), ), ), ); }, ), ); } } /// 三段式分段进度条(对标 SegmentedProgressBar.vue;progress:0~100) class SegmentedProgressBar extends StatelessWidget { const SegmentedProgressBar({super.key, required this.progress}); final double progress; static const Color _green1 = Color(0xFF1BC26E); static const Color _green2 = Color(0xFF7ED8AA); /// 与 Vue updateBarProgress 完全一致的分段算法 List _segmentPercents(double p) { double bar1; if (p >= 33) { bar1 = 100; } else { bar1 = (p / 33 * 100).clamp(0, 100).toDouble(); } double bar2; if (p >= 66) { bar2 = 100; } else if (p > 33) { bar2 = ((p - 33) / 33 * 100).clamp(0, 100).toDouble(); } else { bar2 = 0; } double bar3; if (p >= 100) { bar3 = 100; } else if (p > 66) { bar3 = ((p - 66) / 34 * 100).clamp(0, 100).toDouble(); } else { bar3 = 0; } return [bar1, bar2, bar3]; } @override Widget build(BuildContext context) { final segs = _segmentPercents(progress); return Row( children: [ for (var i = 0; i < 3; i++) ...[ if (i > 0) SizedBox(width: 5.w), Expanded( child: GradientProgressBar( percent: segs[i], height: 6, colors: const [_green1, _green2], ), ), ], ], ); } }