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();
}
}
运行效果

浙公网安备 33010602011771号