自己实现一个AnimationPlayer类
AnimationPlayer类
public partial class AnimationPlayer : ObservableObject{private readonly DispatcherTimer timer;private DateTime? startTime;private DateTime? pauseTime;private bool isRunning;[ObservableProperty]private double _speed = 1.0;[ObservableProperty]private TimeSpan _duration = TimeSpan.FromSeconds(10);[ObservableProperty]private double _progress;[ObservableProperty]private string _timeText = "[[ stopped ]]";[ObservableProperty]private bool _canPause = false;[ObservableProperty]private bool _canResume = false;[ObservableProperty]private bool _canStop = false;// 用户定义的属性应用逻辑public Action<double>? ApplyAction { get; set; }public AnimationPlayer(){timer = new DispatcherTimer{Interval = TimeSpan.FromMilliseconds(50)};timer.Tick += (_, __) => UpdateProgress();}// 开始播放public void Start(){startTime = DateTime.Now;pauseTime = null;isRunning = true;timer.Start();UpdateStates();}// 暂停播放public void Pause(){if (!isRunning) return;pauseTime = DateTime.Now;isRunning = false;timer.Stop();UpdateStates();}// 恢复播放public void Resume(){if (isRunning || startTime == null || pauseTime == null) return;var pausedDuration = DateTime.Now - pauseTime.Value;startTime += pausedDuration;pauseTime = null;isRunning = true;timer.Start();UpdateStates();}// 停止播放public void Stop(){isRunning = false;timer.Stop();startTime = null;pauseTime = null;Progress = 0;TimeText = "[[ stopped ]]";ApplyAction?.Invoke(0);UpdateStates();}// 跳转到指定时间点public void Seek(TimeSpan offset){if (startTime == null) return;startTime = DateTime.Now - TimeSpan.FromTicks((long)(offset.Ticks / Speed));}private void UpdateProgress(){if (startTime == null) return;TimeSpan elapsed;if (isRunning){elapsed = (DateTime.Now - startTime.Value) * Speed;}else if (pauseTime != null){elapsed = (pauseTime.Value - startTime.Value) * Speed;}else{elapsed = TimeSpan.Zero;}if (elapsed >= Duration){elapsed = Duration;isRunning = false;timer.Stop();}Progress = Math.Clamp(elapsed.TotalSeconds / Duration.TotalSeconds, 0, 1);// 带毫秒TimeText = elapsed.ToString(@"hh\:mm\:ss\.ffff");ApplyAction?.Invoke(Progress);UpdateStates();}// 更新 CanPause/CanResume/CanStop 状态private void UpdateStates(){CanPause = isRunning;CanResume = !isRunning && startTime != null && pauseTime != null;CanStop = startTime != null;}}
AnimationPlayerTest.axaml代码
<Window xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Height="396" Width="360.8"x:Class="AvaloniaUI.AnimationPlayerTest"xmlns:local="using:Shares.Avalonia"x:DataType="local:AnimationPlayer"Title="AnimationPlayerTest"><Grid RowDefinitions="auto,auto,auto,auto,auto"><Grid><Image Source="avares://AvaloniaUI/Resources/Images/night.jpg"/><Image Source="avares://AvaloniaUI/Resources/Images/day.jpg" Name="imgDay"/></Grid><StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" Margin="5" VerticalAlignment="Top"><Button Name="cmdStart" Content="Start"/><Button Name="cmdPause" Content="Pause" IsEnabled="{Binding CanPause}"/><Button Name="cmdResume" Content="Resume" IsEnabled="{Binding CanResume}"/><Button Name="cmdStop" Content="Stop" IsEnabled="{Binding CanStop}"/><Button Name="cmdMiddle" Content="Move To Middle"/></StackPanel><TextBlock Grid.Row="2" Name="lblTime" HorizontalAlignment="Center"></TextBlock><Grid Grid.Row="3" Margin="5" ColumnDefinitions="auto,*"> <TextBlock Margin="0,15,5,0">Speed:</TextBlock><Slider Grid.Column="1" Name="sldSpeed" Minimum="0.1" Maximum="3" Value="1" TickPlacement="BottomRight" TickFrequency="0.1"/></Grid><ProgressBar Grid.Row="4" Margin="0,5,0,0" Height="10" Name="progressBar" Minimum="0" Maximum="1"/></Grid> </Window>
AnimationPlayerTest.axaml.cs代码
using Avalonia; using Avalonia.Animation; using Avalonia.Controls; using Avalonia.Markup.Xaml; using Shares.Avalonia; using System;namespace AvaloniaUI;public partial class AnimationPlayerTest : Window {private readonly AnimationPlayer? player;public AnimationPlayerTest(){InitializeComponent();player = new AnimationPlayer{Duration = TimeSpan.FromSeconds(10),Speed = 1.0,ApplyAction = progress =>{// 控制 imgDay 的透明度[1,0]imgDay.Opacity = 1 - progress;// 更新进度条progressBar.Value = progress;// 更新时间文本lblTime.Text = player?.TimeText;}};// 绑定按钮cmdStart.Click += (_, _) => player.Start();cmdPause.Click += (_, _) => player.Pause();cmdResume.Click += (_, _) => player.Resume();cmdStop.Click += (_, _) => player.Stop();cmdMiddle.Click += (_, _) => player.Seek(TimeSpan.FromSeconds(5));// 绑定速度sldSpeed.ValueChanged += (_, _) =>{player.Speed = sldSpeed.Value;};this.DataContext = player;} }
运行效果