ReusableFollowExample.axaml代码
<UserControl 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" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" xmlns:local="using:AvaloniaUI" x:Class="AvaloniaUI.ReusableFollowExample"> <Canvas Background="Transparent"> <!-- 红色方块 --> <local:FollowMouseCanvas Canvas.Left="0" Canvas.Top="0" Width="50" Height="50" Background="Red"> <!-- 可以在这里放更多内容 --> </local:FollowMouseCanvas> <!-- 绿色方块 --> <local:FollowMouseCanvas Canvas.Left="300" Canvas.Top="0" Width="50" Height="50" Background="Green"> </local:FollowMouseCanvas> <!-- 蓝色方块 --> <local:FollowMouseCanvas Canvas.Left="0" Canvas.Top="300" Width="50" Height="50" Background="Blue"> </local:FollowMouseCanvas> </Canvas> </UserControl>
ReusableFollowExample.axaml.cs代码
using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.VisualTree; using Shares.Avalonia; using System; namespace AvaloniaUI; public class FollowMouseCanvas : Canvas { private Vector velocity; private Point lastMouse; private Canvas? parentCanvas; private readonly AnimationPlayer player = new AnimationPlayer(); public FollowMouseCanvas() { player.Fps = 60; player.Loop = true; player.Duration = double.MaxValue; player.At(0).PlayGlobal(UpdatePosition); this.AttachedToVisualTree += (_, __) => { EnsureParent(); player.Start(); }; } private void EnsureParent() { parentCanvas = this.GetVisualParent() as Canvas; if (parentCanvas != null) { parentCanvas.PointerMoved += OnPointerMoved; } } private void OnPointerMoved(object? sender, PointerEventArgs e) { if (parentCanvas != null) lastMouse = e.GetPosition(parentCanvas); } private void UpdatePosition(double progress) { if (parentCanvas == null) return; double left = Canvas.GetLeft(this); double top = Canvas.GetTop(this); if (double.IsNaN(left)) left = 0; if (double.IsNaN(top)) top = 0; var location = new Point(left, top); var toMouse = lastMouse - location; // 根据 progress 做周期性调制,比如让速度在一个周期中变化 double followForce = 0.01 + 0.005 * Math.Sin(progress * 2 * Math.PI * 2); // 2Hz波动 double drag = 0.8 + 0.1 * Math.Sin(progress * 2 * Math.PI); // 阻尼轻微变化 velocity += toMouse * followForce; velocity *= drag; location += velocity; Canvas.SetLeft(this, location.X); Canvas.SetTop(this, location.Y); } } public partial class ReusableFollowExample : UserControl { public ReusableFollowExample() { InitializeComponent(); } }
运行效果