.NET MAUI中如何实现支持自定义区间动画的不确定进度条
.NET MAUI 指定区间往返式不确定进度条实现方案
原生ProgressBar控件确实没有内置区间循环动画能力,可以通过以下两种方案实现需求,不需要引入第三方控件。
方案1:基于原生动画API实现轻量化区间循环(推荐)
直接使用MAUI内置的Animation类和ProgressTo方法组合,实现自定义区间的往返循环动画,支持自定义进度范围、动画时长、缓动效果,代码侵入性最低。
首先为ProgressBar写通用扩展方法,封装动画的启动和停止逻辑,支持取消令牌避免内存泄漏:
public static class ProgressBarExtensions { /// <summary> /// 启动不确定进度的区间往返循环动画 /// </summary> /// <param name="minProgress">区间最小进度值,范围0-1</param> /// <param name="maxProgress">区间最大进度值,范围0-1</param> /// <param name="singleDirectionDuration">单方向(最小到最大/最大到最小)动画时长,单位毫秒</param> /// <param name="cancellationToken">动画取消令牌,页面销毁/操作结束时触发取消</param> public static void StartIndeterminateLoop( this ProgressBar progressBar, double minProgress = 0.2, double maxProgress = 0.8, uint singleDirectionDuration = 800, CancellationToken cancellationToken = default) { progressBar.Progress = minProgress; var loopAnimation = new Animation(async _ => { if (cancellationToken.IsCancellationRequested) return; // 从最小值平滑过渡到最大值 await progressBar.ProgressTo(maxProgress, singleDirectionDuration, Easing.CubicInOut); if (cancellationToken.IsCancellationRequested) return; // 从最大值平滑过渡回最小值 await progressBar.ProgressTo(minProgress, singleDirectionDuration, Easing.CubicInOut); }, minProgress, maxProgress); // 提交动画,设置为持续循环直到收到取消信号 loopAnimation.Commit( owner: progressBar, name: "IndeterminateProgressLoop", rate: 16, repeat: () => !cancellationToken.IsCancellationRequested); } /// <summary> /// 停止不确定进度动画 /// </summary> /// <param name="finalProgress">动画停止后最终展示的进度值,默认1(100%)</param> public static void StopIndeterminateLoop(this ProgressBar progressBar, double finalProgress = 1d) { progressBar.AbortAnimation("IndeterminateProgressLoop"); progressBar.ProgressTo(finalProgress, 250, Easing.CubicOut); } }
调用方式非常简单,在长耗时操作启动时开启动画,操作结束后停止即可:
// 初始化取消令牌源 var animationCts = new CancellationTokenSource(); try { // 启动25%-50%区间的往返动画,单趟动画时长600毫秒 progressBar.StartIndeterminateLoop( minProgress: 0.25, maxProgress: 0.5, singleDirectionDuration: 600, cancellationToken: animationCts.Token); // 执行你的长耗时业务逻辑 await RunLongRunningBusinessAsync(); } finally { // 无论操作成功/失败/取消,都停止动画释放资源 animationCts.Cancel(); progressBar.StopIndeterminateLoop(); animationCts.Dispose(); }
方案2:自定义绘制实现完全对齐设计规范的效果
如果需要完全匹配Material设计规范中不确定进度条的动效(包含活动块宽度动态变化、滑动节奏匹配),可以通过GraphicsView自绘实现,自由度更高:
- 自定义可绑定的动画进度属性,值范围0-1,用循环动画持续驱动该值变化
- 重写绘制逻辑,根据当前动画进度值动态计算活动进度块的位置、宽度,绘制轨道和活动块
- 动画驱动逻辑和方案1一致,和UI刷新帧率同步,不会出现卡顿
注意事项
- 不要用
while(true)+Task.Delay的方式手动修改Progress值实现动画,这种方式无法和UI刷新频率同步,容易出现掉帧、卡顿问题 - 必须在页面消失、长操作结束时主动中止动画,避免动画持续运行占用UI线程资源、引发内存泄漏
- 默认使用
CubicInOut缓动函数更符合通用设计动效节奏,如果需要匀速动画,将代码中的Easing替换为Easing.Linear即可
内容的提问来源于stack exchange,提问作者John Doe
相关产品推荐
相关产品推荐

