You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin.Forms投篮计时器精度异常及暂停续计时问题咨询

投篮计时器精准实现方案

嘿,刚接触Xamarin就能动手做投篮计时器,很棒!你的现有代码遇到的计时精度不准、暂停重启跳秒问题,主要是因为用了System.Timers.Timer的固定间隔减数值的方式——这种方式很容易因为计时器本身的误差累积导致不准,而且暂停后没记录实际流逝的时间,重启自然会跳秒。

咱们换个思路,用**Stopwatch+DispatcherTimer**的组合来实现,这能保证时间计算的精准性,同时完美支持暂停后从当前位置继续计时。

问题根源分析

  • System.Timers.Timer的间隔不是绝对精准的,每次Elapsed事件触发时间有偏差,多次累积就会导致计时不准
  • 暂停后重启时,没有记录到暂停时已经流逝的实际时间,而是直接继续减固定值,必然会跳秒
  • 最后一秒的0.01秒递减逻辑依赖10ms的计时器间隔,但计时器触发不保证绝对准时,误差会被放大

优化后的完整代码

public partial class MainPage : ContentPage 
{ 
    private DispatcherTimer _timer; 
    private Stopwatch _stopwatch;
    private double _totalDuration = 30; // 总计时时长30秒
    private double _remainingTime;

    public MainPage() 
    { 
        InitializeComponent(); 
        // 初始化DispatcherTimer,10ms间隔保证最后一秒的小数显示流畅
        _timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(10) };
        _timer.Tick += OnTimerTick;
        
        _stopwatch = new Stopwatch();
        _remainingTime = _totalDuration;
        UpdateTimerDisplay(); // 初始显示30
    } 

    private void BtnStart_Clicked(object sender, EventArgs e) 
    { 
        if (!_timer.IsEnabled)
        {
            _stopwatch.Start();
            _timer.Start();
        }
    } 

    private void BtnPause_Clicked(object sender, EventArgs e) 
    { 
        _timer.Stop();
        _stopwatch.Stop();
        
        // 记录暂停时的剩余时间,重置秒表以便下次启动重新计时
        _remainingTime -= _stopwatch.Elapsed.TotalSeconds;
        _stopwatch.Reset();
    } 

    private void OnTimerTick(object sender, EventArgs e) 
    { 
        // 用秒表的实际流逝时间计算剩余时长,完全避免累积误差
        double currentRemaining = _remainingTime - _stopwatch.Elapsed.TotalSeconds;
        
        // 处理计时结束的情况
        if (currentRemaining <= 0)
        {
            currentRemaining = 0;
            _timer.Stop();
            _stopwatch.Stop();
        }
        
        UpdateTimerDisplay(currentRemaining);
    }

    private void UpdateTimerDisplay(double time = 30)
    {
        // 根据剩余时间切换显示格式:大于1秒显示整数,最后1秒显示两位小数
        lblTimer.Text = time > 1 
            ? time.ToString("0") 
            : time.ToString("0.00");
    }
}

方案优势说明

  • 精准无误差:Stopwatch基于系统高分辨率计时器,能精确记录实际流逝的时间,剩余时间计算完全依赖真实流逝时长,不会有累积误差
  • 暂停续接流畅:暂停时会计算并保存当前剩余时间,重启时秒表从零开始累加,再用剩余时间减去累加值,完美实现从暂停点继续
  • UI线程友好:DispatcherTimer直接在UI线程运行,不需要手动调用Device.BeginInvokeOnMainThread更新UI,避免线程问题
  • 显示逻辑清晰:通过单独的UpdateTimerDisplay方法处理显示格式,大于1秒显示整数,最后1秒自动切换为两位小数,符合需求

小细节提示

  • 如果希望最后一秒的小数显示更平滑,可以把DispatcherTimer的间隔调小到5ms,但10ms已经足够流畅且不会过多占用资源
  • 计时结束时可以添加额外逻辑,比如播放提示音或者改变UI样式,增强用户体验

内容的提问来源于stack exchange,提问作者Sebastiaan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:51:51