系統(tǒng)組件
- LinearProgressIndicator 是 Flutter 中用于展示線性進(jìn)度的組件,適用于顯示操作的進(jìn)度狀態(tài)。
1. 不確定進(jìn)度(默認(rèn))
- 不設(shè)置 value 屬性,組件會(huì)顯示循環(huán)動(dòng)畫
- 適用于:網(wǎng)絡(luò)請(qǐng)求、數(shù)據(jù)加載等未知完成時(shí)間的場(chǎng)景
LinearProgressIndicator()

循環(huán)動(dòng)畫
2. 確定進(jìn)度
- 設(shè)置 value 屬性(范圍 0.0-1.0),控制進(jìn)度顯示比例
- 適用于:文件下載、任務(wù)進(jìn)度等可量化的場(chǎng)景
LinearProgressIndicator(
value: 0.6, // 顯示60%進(jìn)度
)

固定進(jìn)度
3. 自定義樣式
- backgroundColor:未填充部分的背景色
- valueColor:進(jìn)度填充顏色(需用 AlwaysStoppedAnimation 包裹)
valueColor屬性優(yōu)先。也可以用color屬性,更簡(jiǎn)單
- minHeight:進(jìn)度條高度(默認(rèn)較細(xì),可自定義)
- borderRadius: 圓角
LinearProgressIndicator(
value: 0.6, // 顯示60%進(jìn)度
backgroundColor: Colors.grey,
color: Colors.red,
minHeight: 8,
borderRadius: BorderRadius.circular(4),
),

圓角等屬性
小結(jié)
- 大多數(shù)情況,LinearProgressIndicator足夠用了,固定的指示器顏色,背景色,圓角等都是常用屬性。
- valueColor用于顏色動(dòng)畫,使用場(chǎng)景不多,還是直接用color屬性更簡(jiǎn)單方便。
- 設(shè)計(jì)稿中的漸變色沒有屬性可以設(shè)置,需要自定義實(shí)現(xiàn)。
自定義實(shí)現(xiàn)
- 方案1:在一個(gè)Stack組件中放2個(gè)Container,一個(gè)表示背景,一個(gè)表示指示器,這是最容易想到的方法。
- 方案2:通過FractionallySizedBox根據(jù)進(jìn)度值控制寬度;
Container(
width: 200,
height: 100, // 父容器固定高度100
color: Colors.grey[200],
child: FractionallySizedBox(
heightFactor: 0.8, // 高度為父容器的80%
child: Container(color: Colors.green),
),
)
- 通過Container,就可以實(shí)現(xiàn)顏色漸變效果
動(dòng)畫
- 大多數(shù)情況,不需要?jiǎng)赢?,能固定顯示進(jìn)度可以了;
- 顏色動(dòng)畫用的場(chǎng)景不多,效果也不是很明顯;
- 動(dòng)畫大多數(shù)是對(duì)于進(jìn)度參數(shù),也就是value參數(shù)。
- 外部設(shè)置,比如0.6,就是value的最終狀態(tài);可以從0開始逐漸增加到value的值;這種變化比較明顯
組件封裝
- 由于想要?jiǎng)赢嬚故緑alue值的變化,所以用StatefulWidget
-
除了進(jìn)度展示,還有前后的文字說明,統(tǒng)一放在Row組件中
組件部分
class ProcessWidget extends StatefulWidget {
const ProcessWidget({
super.key,
required this.progress,
this.margin,
this.padding,
this.height,
this.backgroundColor,
this.beginColor,
this.endColor,
this.milliseconds,
this.showLabel = true,
this.showProgress = true,
this.labelText = "",
this.labelStyle,
});
final double progress;
final EdgeInsetsGeometry? margin;
final EdgeInsetsGeometry? padding;
final double? height;
final Color? backgroundColor;
final Color? beginColor;
final Color? endColor;
final int? milliseconds;
final bool showLabel;
final bool showProgress;
final String labelText;
final TextStyle? labelStyle;
@override
State<ProcessWidget> createState() => _ProcessWidgetState();
}
class _ProcessWidgetState extends State<ProcessWidget> with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _progressAnimation;
@override
void initState() {
super.initState();
// 1. 初始化動(dòng)畫控制器
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: widget.milliseconds ?? 600), // 動(dòng)畫持續(xù)時(shí)間
);
// 2. 創(chuàng)建進(jìn)度動(dòng)畫(0.0 -> progress)
_progressAnimation = Tween<double>(begin: 0.0, end: widget.progress).animate(
CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut, // 動(dòng)畫曲線
),
);
// 4. 啟動(dòng)動(dòng)畫
_animationController.forward();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
double height = widget.height ?? 8.r;
double radius = height / 2;
return Container(
margin: widget.margin,
padding: widget.padding,
child: Row(
children: [
Visibility(
visible: widget.showLabel,
child: Container(
margin: EdgeInsets.only(right: 8.r),
constraints: BoxConstraints(minWidth: 60.r, maxWidth: 120.r),
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(widget.labelText, style: widget.labelStyle ?? StyleUtils.ts_1f_12_500),
),
),
),
Expanded(
child: AnimatedBuilder(
animation: _progressAnimation,
builder: (context, child) {
return Container(
height: height,
decoration: BoxDecoration(
color: widget.backgroundColor ?? ColorUtils.c_f8f8f8,
borderRadius: BorderRadius.circular(radius),
),
child: FractionallySizedBox(
widthFactor: _progressAnimation.value,
alignment: Alignment.centerLeft,
child: Container(
height: height,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(radius),
gradient: LinearGradient(
colors: [widget.beginColor ?? ColorUtils.c_ffbc52, widget.endColor ?? ColorUtils.c_ff6f2a],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
),
),
),
);
},
),
),
Visibility(
visible: widget.showProgress,
child: Container(
margin: EdgeInsets.only(left: 8.r),
child: Text("${(widget.progress * 100).toStringAsFixed(0)}%", style: StyleUtils.ts_1f_13_500),
),
),
],
),
);
}
}
