查看: 246|回复: 3

Flutter鸿蒙开发实战:CircularProgressIndica

[复制链接]
发表于 昨天 11:00 | 显示全部楼层 |阅读模式
在鸿蒙平台上做 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 确定模式

不确定模式适合网络请求、页面初始化等耗时未知的场景。代码示例:
  1. CircularProgressIndicator(),
  2. CircularProgressIndicator(color: Colors.blue, strokeWidth: 4.0),
  3. CircularProgressIndicator(color: Colors.red, strokeWidth: 6.0),
复制代码

确定模式必须配合 AnimationController 驱动,否则进度静态不动。我习惯在 StatefulWidget 中混入 TickerProviderStateMixin 来管理动画控制器:
  1. late final AnimationController _progressCtrl;
  2. @override
  3. void initState() {
  4.   super.initState();
  5.   _progressCtrl = AnimationController(
  6.     vsync: this,
  7.     duration: const Duration(seconds: 3),
  8.   );
  9.   _progressCtrl.addListener(() => setState(() {}));
  10. }
复制代码
注意 dispose 中务必释放控制器,否则控制台会报 Ticker 泄漏警告。AnimationController 的 value 范围是 0.0~1.0,与 CircularProgressIndicator 的 value 天然对齐,无需额外映射。

样式对比与容器约束

不同参数组合效果差异明显:
  1. const CircularProgressIndicator(),
  2. const CircularProgressIndicator(strokeWidth: 12),
  3. CircularProgressIndicator(
  4.   value: 0.7,
  5.   strokeWidth: 6,
  6.   color: Colors.blue,
  7.   backgroundColor: Colors.blue.shade50,
  8. ),
复制代码

踩坑点:strokeWidth 不能超过容器最短边的一半。内部绘制时圆弧半径 = (size.shortestSide - strokeWidth) / 2,若 strokeWidth 大于 shortestSide,半径变为负数,圆弧边缘被截断。最佳实践是让 strokeWidth 不超过容器最短边的 1/3。

百分比文字与 Stack 布局

将百分比文字叠在进度圈中间,推荐用 Stack 配合 SizedBox 约束容器尺寸:
  1. SizedBox(
  2.   width: 120,
  3.   height: 120,
  4.   child: Stack(
  5.     alignment: Alignment.center,
  6.     children: [
  7.       CircularProgressIndicator(
  8.         value: _customValue,
  9.         strokeWidth: 10,
  10.         color: Colors.teal,
  11.         backgroundColor: Colors.teal.shade100,
  12.       ),
  13.       Text(
  14.         '${(_customValue * 100).toInt()}%',
  15.         style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
  16.       ),
  17.     ],
  18.   ),
  19. ),
  20. Slider(
  21.   value: _customValue,
  22.   onChanged: (v) => setState(() => _customValue = v),
  23. ),
复制代码
若不给 Stack 外层设固定尺寸,CircularProgressIndicator 会撑满父容器,文字移到卡片正中央而非进度圈中心。

动画曲线与自定义玩法

默认 AnimationController 使用线性插值,感觉偏硬。可改用 CurvedAnimation 实现缓入缓出效果:
  1. final animation = CurvedAnimation(
  2.   parent: _progressCtrl,
  3.   curve: Curves.easeInOut,
  4. );
  5. // 使用 animation.value 替代 _progressCtrl.value
复制代码

还可利用 AnimatedBuilder 在进度变化时同时改变颜色:
  1. AnimatedBuilder(
  2.   animation: _progressCtrl,
  3.   builder: (context, child) {
  4.     return CircularProgressIndicator(
  5.       value: _progressCtrl.value,
  6.       color: Color.lerp(Colors.blue, Colors.red, _progressCtrl.value),
  7.       strokeWidth: 6,
  8.     );
  9.   },
  10. )
复制代码

与 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,以保证跨主题一致性:
  1. CircularProgressIndicator(
  2.   color: Theme.of(context).colorScheme.primary,
  3.   backgroundColor: Theme.of(context).colorScheme.surfaceContainerHighest,
  4. )
复制代码
- 避免重复点击:在动画未完成时再次触发 forward() 会导致进度条跳动。可先判是否已完成,完成则 reverse(),否则从头开始。

总结

CircularProgressIndicator 看似简单,但要做得精致需注意容器尺寸约束、动画驱动方式、底层圈选择、跨主题适配等细节。对比 ArkTS 原生组件,Flutter 提供更高的灵活性和流畅度,适合追求统一多端体验的鸿蒙应用开发。一步到位的方法是在项目里封装一个通用加载组件,统一管理动画控制器和状态,避免每次手动编写重复代码。
回复

使用道具 举报

发表于 昨天 11:10 | 显示全部楼层

Re: Flutter鸿蒙开发实战:CircularProgressIndica

感谢楼主分享,非常详细的实战指南!从基础参数到动画驱动,再到与 ArkTS 的对比,覆盖了日常开发中的核心场景。特别是 strokeWidth 不能超过容器最短边一半的踩坑点,之前确实遇到过,当时排查了挺久,现在终于明白原理了。另外用 Stack 嵌套固定尺寸 SizedBox 显示百分比文字的做法也很实用,省了自己摸索布局的时间。期待楼主后续还能分享一些鸿蒙平台特有的性能调优经验!
回复 支持 反对

使用道具 举报

发表于 昨天 11:10 | 显示全部楼层

Re: Flutter鸿蒙开发实战:CircularProgressIndica

谢谢楼主分享这么详细的实战总结!最近正好在转鸿蒙 Flutter 开发,CircularProgressIndicator 的坑确实多。特别是你提到的 strokeWidth 不能超过容器最短边一半这点,我之前没注意,真机上圆弧直接被切掉一半,排查了半天才找到原因。另外用 Stack 加 SizedBox 约束百分比文字位置也很实用,我之前遇到过文字跑偏的问题,照着你的方案调一下。想问下在 nova12u 上动画驱动时,如果同时多个进度条会掉帧吗?有没有推荐的最佳实践?
回复 支持 反对

使用道具 举报

发表于 昨天 11:10 | 显示全部楼层

Re: Flutter鸿蒙开发实战:CircularProgressIndica

楼主总结得很全面,尤其是 strokeWidth 不能超过容器最短边一半的踩坑点,之前在别的平台上我也踩过类似的坑。另外 Stack 配合固定 SizedBox 来居中百分比文字这个小技巧很实用,不设尺寸的话文字确实容易跑偏。想问一下,在确定模式下默认的起始位置是右侧(3点钟方向),如果想改成从顶部(12点钟方向)开始,目前 Flutter 有没有参数直接控制,还是需要自己旋转 Transform?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-7-21 07:19 , Processed in 0.029219 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部