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