mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-21 16:14:28 +08:00
0.2.5
课表组件、天气组件全面升级。
This commit is contained in:
136
LanMontainDesktop/Behaviors/PopupIntroAnimationBehavior.cs
Normal file
136
LanMontainDesktop/Behaviors/PopupIntroAnimationBehavior.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation.Easings;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Rendering.Composition;
|
||||
|
||||
namespace LanMontainDesktop.Behaviors;
|
||||
|
||||
public class PopupIntroAnimationBehavior
|
||||
{
|
||||
public static readonly AttachedProperty<bool> IsEnabledProperty =
|
||||
AvaloniaProperty.RegisterAttached<PopupIntroAnimationBehavior, Control, bool>("IsEnabled");
|
||||
|
||||
private static readonly AttachedProperty<bool> IsHookedProperty =
|
||||
AvaloniaProperty.RegisterAttached<PopupIntroAnimationBehavior, Control, bool>("IsHooked");
|
||||
|
||||
static PopupIntroAnimationBehavior()
|
||||
{
|
||||
IsEnabledProperty.Changed.AddClassHandler<Control>(OnIsEnabledChanged);
|
||||
}
|
||||
|
||||
public static void SetIsEnabled(Control control, bool value)
|
||||
{
|
||||
control.SetValue(IsEnabledProperty, value);
|
||||
}
|
||||
|
||||
public static bool GetIsEnabled(Control control)
|
||||
{
|
||||
return control.GetValue(IsEnabledProperty);
|
||||
}
|
||||
|
||||
private static bool GetIsHooked(Control control)
|
||||
{
|
||||
return control.GetValue(IsHookedProperty);
|
||||
}
|
||||
|
||||
private static void SetIsHooked(Control control, bool value)
|
||||
{
|
||||
control.SetValue(IsHookedProperty, value);
|
||||
}
|
||||
|
||||
private static void OnIsEnabledChanged(Control control, AvaloniaPropertyChangedEventArgs args)
|
||||
{
|
||||
if (args.NewValue is not bool isEnabled || !isEnabled || GetIsHooked(control))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (control)
|
||||
{
|
||||
case PopupRoot popupRoot:
|
||||
popupRoot.Opened += OnPopupOpened;
|
||||
SetIsHooked(popupRoot, true);
|
||||
break;
|
||||
case OverlayPopupHost overlayPopupHost:
|
||||
overlayPopupHost.AttachedToVisualTree += OnOverlayPopupHostAttached;
|
||||
SetIsHooked(overlayPopupHost, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnPopupOpened(object? sender, EventArgs e)
|
||||
{
|
||||
if (sender is Control control)
|
||||
{
|
||||
PlayIntroAnimation(control);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnOverlayPopupHostAttached(object? sender, VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
if (sender is Control control)
|
||||
{
|
||||
PlayIntroAnimation(control);
|
||||
}
|
||||
}
|
||||
|
||||
private static void PlayIntroAnimation(Control control)
|
||||
{
|
||||
var compositionVisual = ElementComposition.GetElementVisual(control);
|
||||
if (compositionVisual is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var popup = control.Parent as Popup;
|
||||
compositionVisual.CenterPoint = ResolveCenterPoint(
|
||||
popup?.Placement ?? PlacementMode.Pointer,
|
||||
control.Bounds.Size,
|
||||
compositionVisual.CenterPoint);
|
||||
|
||||
var compositor = compositionVisual.Compositor;
|
||||
|
||||
var opacityAnimation = compositor.CreateScalarKeyFrameAnimation();
|
||||
opacityAnimation.Target = nameof(compositionVisual.Opacity);
|
||||
opacityAnimation.Duration = TimeSpan.FromMilliseconds(160);
|
||||
opacityAnimation.InsertKeyFrame(0f, 0f);
|
||||
opacityAnimation.InsertKeyFrame(1f, 1f, Easing.Parse("0.22, 1, 0.36, 1"));
|
||||
compositionVisual.StartAnimation(nameof(compositionVisual.Opacity), opacityAnimation);
|
||||
|
||||
var scaleAnimation = compositor.CreateVector3DKeyFrameAnimation();
|
||||
scaleAnimation.Target = nameof(compositionVisual.Scale);
|
||||
scaleAnimation.Duration = TimeSpan.FromMilliseconds(160);
|
||||
scaleAnimation.InsertKeyFrame(0f, compositionVisual.Scale with { X = 0.94, Y = 0.94 });
|
||||
scaleAnimation.InsertKeyFrame(1f, compositionVisual.Scale with { X = 1, Y = 1 }, Easing.Parse("0.22, 1, 0.36, 1"));
|
||||
compositionVisual.StartAnimation(nameof(compositionVisual.Scale), scaleAnimation);
|
||||
}
|
||||
|
||||
private static Vector3D ResolveCenterPoint(PlacementMode placement, Size size, Vector3D fallback)
|
||||
{
|
||||
var relative = placement switch
|
||||
{
|
||||
PlacementMode.Bottom => new RelativePoint(0.5, 0.0, RelativeUnit.Relative),
|
||||
PlacementMode.Left => new RelativePoint(1.0, 0.5, RelativeUnit.Relative),
|
||||
PlacementMode.Right => new RelativePoint(0.0, 0.5, RelativeUnit.Relative),
|
||||
PlacementMode.Top => new RelativePoint(0.5, 1.0, RelativeUnit.Relative),
|
||||
PlacementMode.Pointer => new RelativePoint(0.0, 0.0, RelativeUnit.Relative),
|
||||
PlacementMode.BottomEdgeAlignedLeft => new RelativePoint(0.0, 0.0, RelativeUnit.Relative),
|
||||
PlacementMode.BottomEdgeAlignedRight => new RelativePoint(1.0, 0.0, RelativeUnit.Relative),
|
||||
PlacementMode.LeftEdgeAlignedTop => new RelativePoint(1.0, 1.0, RelativeUnit.Relative),
|
||||
PlacementMode.LeftEdgeAlignedBottom => new RelativePoint(1.0, 0.0, RelativeUnit.Relative),
|
||||
PlacementMode.RightEdgeAlignedTop => new RelativePoint(0.0, 1.0, RelativeUnit.Relative),
|
||||
PlacementMode.RightEdgeAlignedBottom => new RelativePoint(0.0, 0.0, RelativeUnit.Relative),
|
||||
PlacementMode.TopEdgeAlignedLeft => new RelativePoint(0.0, 1.0, RelativeUnit.Relative),
|
||||
PlacementMode.TopEdgeAlignedRight => new RelativePoint(1.0, 1.0, RelativeUnit.Relative),
|
||||
_ => new RelativePoint(0.5, 0.5, RelativeUnit.Relative)
|
||||
};
|
||||
|
||||
return fallback with
|
||||
{
|
||||
X = size.Width * relative.Point.X,
|
||||
Y = size.Height * relative.Point.Y
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user