FrameBasedAnimation.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="463.2" x:Class="AvaloniaUI.FrameBasedAnimation" Title="FrameBasedAnimation"> <Grid Margin="3" RowDefinitions="auto,*"> <StackPanel Orientation="Horizontal"> <Button Margin="3" Padding="3" Click="cmdStart_Clicked">Start</Button> <Button Margin="3" Padding="3" Click="cmdStop_Clicked">Stop</Button> </StackPanel> <Canvas Name="canvas" Grid.Row="1" Margin="3"></Canvas> </Grid> </Window>
FrameBasedAnimation.axaml.cs代码
using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Shapes; using Avalonia.Interactivity; using Avalonia.Markup.Xaml; using Avalonia.Media; using Shares.Avalonia; using System; using System.Collections.Generic; using System.Linq; namespace AvaloniaUI; public class EllipseInfo { public Ellipse Ellipse { get; set; } public double VelocityY { get; set; } public bool HasStopped { get; set; } // 当前是否停止 public int BouncesRemaining { get; set; } // 剩余弹跳次数 public double MaxBounceSpeed { get; set; } // 最大反弹初速度 public EllipseInfo(Ellipse ellipse, double velocityY, int bounces, double bounceSpeed) { Ellipse = ellipse; VelocityY = velocityY; HasStopped = false; BouncesRemaining = bounces; MaxBounceSpeed = bounceSpeed; } } public partial class FrameBasedAnimation : Window { private readonly AnimationPlayer player = new AnimationPlayer(); private readonly List<EllipseInfo> ellipses = new(); private readonly Random rand = new Random(); private double accelerationY = 0.1; private int minStartingSpeed = 1; private int maxStartingSpeed = 50; private double speedRatio = 0.1; private int minEllipses = 20; private int maxEllipses = 100; private int ellipseRadius = 10; public FrameBasedAnimation() { InitializeComponent(); player.Duration = 8; // 整个动画总时间(秒),自动清屏 player.At(0) .PlayGlobal(progress => { if (ellipses.Count == 0) { player.Stop(); return; } double bottomLimit = canvas.Bounds.Height - ellipseRadius * 2 - 10; foreach (var info in ellipses) { double top = Canvas.GetTop(info.Ellipse); // 弹跳逻辑 if (info.HasStopped) { if (info.BouncesRemaining > 0 && top >= bottomLimit) { // 随机弹起 info.VelocityY = -rand.NextDouble() * info.MaxBounceSpeed; info.BouncesRemaining--; info.HasStopped = false; // 重新开始运动 } else { Canvas.SetTop(info.Ellipse, bottomLimit); info.VelocityY = 0; continue; } } double newTop = top + info.VelocityY; info.VelocityY += accelerationY; if (newTop >= bottomLimit) { Canvas.SetTop(info.Ellipse, bottomLimit); info.HasStopped = true; } else { Canvas.SetTop(info.Ellipse, newTop); } } }); player.AnimationCompleted += () => { ellipses.Clear(); canvas.Children.Clear(); }; } private void cmdStart_Clicked(object? sender, RoutedEventArgs e) { ellipses.Clear(); canvas.Children.Clear(); int halfCanvasWidth = (int)canvas.Bounds.Width / 2; int ellipseCount = rand.Next(minEllipses, maxEllipses + 1); for (int i = 0; i < ellipseCount; i++) { var ellipse = new Ellipse { Fill = Brushes.LimeGreen, Width = ellipseRadius, Height = ellipseRadius }; Canvas.SetLeft(ellipse, halfCanvasWidth + rand.Next(-halfCanvasWidth, halfCanvasWidth)); Canvas.SetTop(ellipse, 0); canvas.Children.Add(ellipse); var info = new EllipseInfo( ellipse, speedRatio * rand.Next(minStartingSpeed, maxStartingSpeed), rand.Next(0, 3), // 随机弹跳次数 0~2 rand.Next(1,4) //随机反弹速度1~3 ); ellipses.Add(info); } player.Start(); } private void cmdStop_Clicked(object? sender, RoutedEventArgs e) { player.Stop(); ellipses.Clear(); canvas.Children.Clear(); } }
运行效果