如何计算进度条在指定时间内从0%到100%的加载逻辑?
问题分析与解决方案
一、原代码的时间计算逻辑解释
你提到的原代码确实逻辑绕,它的意图是让进度条整体显示约4秒,但拆分了两部分:
- 进度条从0到100需要100次Tick,每次间隔30ms,这部分耗时
100×30=3000ms(3秒) - 进度条满了之后,再等待35次Tick(实际是第36次Tick时触发判断),这部分耗时
36×30=1080ms - 总时长
3000+1080=4080ms,接近4秒,这就是它想凑4秒的逻辑,但计算分散,很容易混淆。
二、针对核心需求的优化方案
你的核心需求是让进度条有可见的加载动画,避免二次加载时一闪而过,类似启动页逻辑,不管实际加载速度,保证进度条至少显示一段时间,同时支持实际加载完成后提前结束动画。
优化思路
- 设定固定的模拟加载最短时长(比如2秒,可自行调整)
- 记录定时器启动时间,每次Tick按时间比例更新进度条
- 监听浏览器加载完成事件,一旦加载完成,立即拉满进度条并结束动画
- 动画结束或进度条拉满时,隐藏进度条显示浏览器
修改后的完整代码
using System; using System.Windows.Forms; using CefSharp; namespace Weather { public partial class GoogleMapsForm : Form { private System.Windows.Forms.Timer _loadingMapTimer; // 模拟加载的最短时长(单位:毫秒),可自行调整 private const int SimulateMinLoadDuration = 2000; // 定时器启动的时间戳 private DateTime _timerStartTime; public GoogleMapsForm() { InitializeComponent(); _loadingMapTimer = new System.Windows.Forms.Timer(); _loadingMapTimer.Interval = 16; // 接近60fps,动画更平滑 progressBar1.Maximum = 100; _loadingMapTimer.Tick += LoadingMapTimer_Tick; WindowState = FormWindowState.Maximized; chromiumWebBrowser1.LoadingStateChanged += ChromiumWebBrowser1_LoadingStateChanged; chromiumWebBrowser1.Load("D:\\Csharp Projects\\Weather\\map.html"); } private void LoadingMapTimer_Tick(object sender, EventArgs e) { var elapsedMs = (DateTime.Now - _timerStartTime).TotalMilliseconds; // 按时间比例计算进度值 var progress = (int)(elapsedMs / SimulateMinLoadDuration * 100); // 进度不超过100 progressBar1.Value = Math.Min(progress, 100); // 进度满或达到模拟时长,结束动画 if (progressBar1.Value >= 100 || elapsedMs >= SimulateMinLoadDuration) { _loadingMapTimer.Stop(); progressBar1.Visible = false; chromiumWebBrowser1.Visible = true; } } private void ChromiumWebBrowser1_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e) { Invoke(new Action(() => { if (e.IsLoading) { chromiumWebBrowser1.Visible = false; progressBar1.Visible = true; // 启动定时器并记录时间 _timerStartTime = DateTime.Now; _loadingMapTimer.Start(); } else { // 实际加载完成,立即拉满进度并结束动画 if (_loadingMapTimer.Enabled) { _loadingMapTimer.Stop(); progressBar1.Value = 100; // 可选:短暂延迟让用户看到满进度,也可以直接隐藏 Task.Delay(100).ContinueWith(_ => Invoke(new Action(() => { progressBar1.Visible = false; chromiumWebBrowser1.Visible = true; }))); } } })); } private void GoogleMapsForm_Load(object sender, EventArgs e) { } } }
代码说明
- 定时器间隔设为16ms,接近60帧每秒,动画更平滑
SimulateMinLoadDuration控制进度条最短显示时长,按需调整数值即可- 实际加载完成时,会先拉满进度条,可选延迟100ms再切换显示,避免进度条一闪而过
- 逻辑直观,时间计算集中,避免原代码的分散判断问题
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

