Flutter鸿蒙开发实战:CircularProgressIndica
在鸿蒙平台上做 Flutter 应用,进度加载组件是绕不开的基础组件。CircularProgressIndicator 虽小,但用好了能提升用户体验,用错了反而会出各种诡异问题。本文基于 Flutter HarmonyOS 6.0 和 nova12u 真机验证,从基础模式、参数配置、动画驱动到与 ArkTS 原生组件的对比,完整梳理该组件的正确姿势。核心参数快速上手
CircularProgressIndicator 的关键参数如下:
- value:传入 null 为不确定模式(无限旋转),传入 0.0~1.0 为确定模式(圆弧按比例填充)。
- strokeWidth:圆弧粗细,默认 4.0 逻辑像素。
- color:圆弧颜色,默认取自主题 ColorScheme.primary。
- backgroundColor:底圈颜色,仅在确定模式下有意义。
- strokeCap:圆弧端头形状,StrokeCap.round 可让端头变圆。
- semanticsLabel:无障碍标签。
不确定模式 vs 确定模式
不确定模式适合网络请求、页面初始化等耗时未知的场景。代码示例:
CircularProgressIndicator(),
CircularProgressIndicator(color: Colors.blue, strokeWidth: 4.0),
CircularProgressIndicator(color: Colors.red, strokeWidth: 6.0),
确定模式必须配合 AnimationController 驱动,否则进度静态不动。我习惯在 StatefulWidget 中混入 TickerProviderStateMixin 来管理动画控制器:
late final AnimationController _progressCtrl;
@override
void initState() {
super.initState();
_progressCtrl = AnimationController(
vsync: this,
duration: const Duration(seconds: 3),
);
_progressCtrl.addListener(() => setState(() {}));
}
注意 dispose 中务必释放控制器,否则控制台会报 Ticker 泄漏警告。AnimationController 的 value 范围是 0.0~1.0,与 CircularProgressIndicator 的 value 天然对齐,无需额外映射。
样式对比与容器约束
不同参数组合效果差异明显:
const CircularProgressIndicator(),
const CircularProgressIndicator(strokeWidth: 12),
CircularProgressIndicator(
value: 0.7,
strokeWidth: 6,
color: Colors.blue,
backgroundColor: Colors.blue.shade50,
),
踩坑点:strokeWidth 不能超过容器最短边的一半。内部绘制时圆弧半径 = (size.shortestSide - strokeWidth) / 2,若 strokeWidth 大于 shortestSide,半径变为负数,圆弧边缘被截断。最佳实践是让 strokeWidth 不超过容器最短边的 1/3。
百分比文字与 Stack 布局
将百分比文字叠在进度圈中间,推荐用 Stack 配合 SizedBox 约束容器尺寸:
SizedBox(
width: 120,
height: 120,
child: Stack(
alignment: Alignment.center,
children: [
CircularProgressIndicator(
value: _customValue,
strokeWidth: 10,
color: Colors.teal,
backgroundColor: Colors.teal.shade100,
),
Text(
'${(_customValue * 100).toInt()}%',
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
),
],
),
),
Slider(
value: _customValue,
onChanged: (v) => setState(() => _customValue = v),
),
若不给 Stack 外层设固定尺寸,CircularProgressIndicator 会撑满父容器,文字移到卡片正中央而非进度圈中心。
动画曲线与自定义玩法
默认 AnimationController 使用线性插值,感觉偏硬。可改用 CurvedAnimation 实现缓入缓出效果:
final animation = CurvedAnimation(
parent: _progressCtrl,
curve: Curves.easeInOut,
);
// 使用 animation.value 替代 _progressCtrl.value
还可利用 AnimatedBuilder 在进度变化时同时改变颜色:
AnimatedBuilder(
animation: _progressCtrl,
builder: (context, child) {
return CircularProgressIndicator(
value: _progressCtrl.value,
color: Color.lerp(Colors.blue, Colors.red, _progressCtrl.value),
strokeWidth: 6,
);
},
)
与 ArkTS 原生组件对比
鸿蒙 ArkTS 提供了 LoadingProgress(不确定模式)和 Progress(确定模式)两个独立组件。对比感受:
1. Flutter 将两种模式整合于同一组件,通过 value 区分,调用更统一;ArkTS 拆成两个组件,语义更清晰但需记忆两个类型名。
2. 自定义能力上 Flutter 更灵活,可调节 strokeCap、backgroundColor,还可配合 AnimatedBuilder 实现复杂过渡;ArkTS 的 Progress 自定义度较低,复杂效果需用 Canvas 自绘。
3. 动画流畅度方面,在 nova12u 上实测 Flutter 旋转更丝滑,ArkTS 的 LoadingProgress 在页面切换时偶有卡顿。
4. 布局方式不同:Flutter 的 CircularProgressIndicator 默认占满可用空间,需用 SizedBox 约束;ArkTS 的组件默认有固定尺寸。
5. ArkTS 的 Progress 内置动画过渡(设 value 后自动补间),Flutter 需手动驱动 AnimationController。
其他注意事项
- strokeCap 在不确定模式下无效,因为闭合环没有端头。确定模式下若 value 接近 1.0(如 0.99),round 会导致起点终点重叠处凸起,建议 value 到 1.0 时隐藏进度圈或显示完成图标。
- Theme 影响:Flutter 3.10+ 默认启用 Material 3,CircularProgressIndicator 使用 indicatorColor 和 trackColor 语义 Token,样式与 Material 2 不同。建议显式传 color 和 backgroundColor,以保证跨主题一致性:
CircularProgressIndicator(
color: Theme.of(context).colorScheme.primary,
backgroundColor: Theme.of(context).colorScheme.surfaceContainerHighest,
)
- 避免重复点击:在动画未完成时再次触发 forward() 会导致进度条跳动。可先判是否已完成,完成则 reverse(),否则从头开始。
总结
CircularProgressIndicator 看似简单,但要做得精致需注意容器尺寸约束、动画驱动方式、底层圈选择、跨主题适配等细节。对比 ArkTS 原生组件,Flutter 提供更高的灵活性和流畅度,适合追求统一多端体验的鸿蒙应用开发。一步到位的方法是在项目里封装一个通用加载组件,统一管理动画控制器和状态,避免每次手动编写重复代码。
Re: Flutter鸿蒙开发实战:CircularProgressIndica
感谢楼主分享,非常详细的实战指南!从基础参数到动画驱动,再到与 ArkTS 的对比,覆盖了日常开发中的核心场景。特别是 strokeWidth 不能超过容器最短边一半的踩坑点,之前确实遇到过,当时排查了挺久,现在终于明白原理了。另外用 Stack 嵌套固定尺寸 SizedBox 显示百分比文字的做法也很实用,省了自己摸索布局的时间。期待楼主后续还能分享一些鸿蒙平台特有的性能调优经验!Re: Flutter鸿蒙开发实战:CircularProgressIndica
谢谢楼主分享这么详细的实战总结!最近正好在转鸿蒙 Flutter 开发,CircularProgressIndicator 的坑确实多。特别是你提到的 strokeWidth 不能超过容器最短边一半这点,我之前没注意,真机上圆弧直接被切掉一半,排查了半天才找到原因。另外用 Stack 加 SizedBox 约束百分比文字位置也很实用,我之前遇到过文字跑偏的问题,照着你的方案调一下。想问下在 nova12u 上动画驱动时,如果同时多个进度条会掉帧吗?有没有推荐的最佳实践?Re: Flutter鸿蒙开发实战:CircularProgressIndica
楼主总结得很全面,尤其是 strokeWidth 不能超过容器最短边一半的踩坑点,之前在别的平台上我也踩过类似的坑。另外 Stack 配合固定 SizedBox 来居中百分比文字这个小技巧很实用,不设尺寸的话文字确实容易跑偏。想问一下,在确定模式下默认的起始位置是右侧(3点钟方向),如果想改成从顶部(12点钟方向)开始,目前 Flutter 有没有参数直接控制,还是需要自己旋转 Transform?
页:
[1]