From 01f97addfa8435aa2244ae720cdcd4dc1265a406 Mon Sep 17 00:00:00 2001 From: CHINBOY Date: Wed, 25 Jun 2025 08:38:20 +0800 Subject: [PATCH] refactor popup motion Now supports setting opening and closing animations --- src/AtomUI.Base/MotionScene/AbstractMotion.cs | 13 +++---- .../MotionScene/CollapseMotions.cs | 4 +- src/AtomUI.Base/MotionScene/FadeMotions.cs | 4 +- src/AtomUI.Base/MotionScene/IMotion.cs | 4 +- src/AtomUI.Base/MotionScene/MoveMotions.cs | 16 ++++---- src/AtomUI.Base/MotionScene/SlideMotions.cs | 16 ++++---- src/AtomUI.Base/MotionScene/ZoomMotions.cs | 24 ++++++------ src/AtomUI.Controls/Flyouts/FlyoutHost.cs | 35 +++++++++++++++++- .../Flyouts/PopupFlyoutBase.cs | 37 +++++++++++++++++-- src/AtomUI.Controls/Popup/Popup.cs | 33 +++++++++++++---- src/AtomUI.Controls/Popup/PopupBuddyLayer.cs | 30 ++++++++++++++- 11 files changed, 161 insertions(+), 55 deletions(-) diff --git a/src/AtomUI.Base/MotionScene/AbstractMotion.cs b/src/AtomUI.Base/MotionScene/AbstractMotion.cs index 2e42ea474..ed5f67a3c 100644 --- a/src/AtomUI.Base/MotionScene/AbstractMotion.cs +++ b/src/AtomUI.Base/MotionScene/AbstractMotion.cs @@ -4,7 +4,6 @@ using AtomUI.Animations; using Avalonia; using Avalonia.Animation; using Avalonia.Animation.Easings; -using Avalonia.Controls; using Avalonia.Media; using Avalonia.Media.Transformation; using Avalonia.ReactiveUI; @@ -12,20 +11,20 @@ using Avalonia.Threading; namespace AtomUI.MotionScene; -internal class AbstractMotion : IMotion +public class AbstractMotion : IMotion { public RelativePoint RenderTransformOrigin { get; protected set; } public IList Animations { get; } public IList Transitions { get; } - public TimeSpan Duration { get; } - public Easing Easing { get; } - public FillMode PropertyValueFillMode { get; } + public TimeSpan Duration { get; set; } + public Easing Easing { get; set; } + public FillMode PropertyValueFillMode { get; set; } public MotionSpiritType SpiritType { get; set; } = MotionSpiritType.Transition; - public AbstractMotion(TimeSpan duration, Easing? easing = null, FillMode fillMode = FillMode.Forward) + public AbstractMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) { Animations = new List(); - Duration = duration; + Duration = duration ?? TimeSpan.FromMilliseconds(300); Easing = easing ?? new LinearEasing(); PropertyValueFillMode = fillMode; Transitions = new List(); diff --git a/src/AtomUI.Base/MotionScene/CollapseMotions.cs b/src/AtomUI.Base/MotionScene/CollapseMotions.cs index f4236335b..ece178599 100644 --- a/src/AtomUI.Base/MotionScene/CollapseMotions.cs +++ b/src/AtomUI.Base/MotionScene/CollapseMotions.cs @@ -9,7 +9,7 @@ internal class CollapseMotion : AbstractMotion public Direction Direction { get; } public CollapseMotion(Direction direction, - TimeSpan duration, + TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CubicEaseOut(), fillMode) @@ -72,7 +72,7 @@ internal class ExpandMotion : AbstractMotion public Direction Direction { get; } public ExpandMotion(Direction direction, - TimeSpan duration, + TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CubicEaseIn(), fillMode) diff --git a/src/AtomUI.Base/MotionScene/FadeMotions.cs b/src/AtomUI.Base/MotionScene/FadeMotions.cs index 67336d7e9..1a1d4a50c 100644 --- a/src/AtomUI.Base/MotionScene/FadeMotions.cs +++ b/src/AtomUI.Base/MotionScene/FadeMotions.cs @@ -7,7 +7,7 @@ namespace AtomUI.MotionScene; internal class FadeInMotion : AbstractMotion { - public FadeInMotion(TimeSpan duration, + public FadeInMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new LinearEasing(), fillMode) @@ -33,7 +33,7 @@ internal class FadeInMotion : AbstractMotion internal class FadeOutMotion : AbstractMotion { - public FadeOutMotion(TimeSpan duration, + public FadeOutMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new LinearEasing(), fillMode) diff --git a/src/AtomUI.Base/MotionScene/IMotion.cs b/src/AtomUI.Base/MotionScene/IMotion.cs index 45dc974a8..58e36bae8 100644 --- a/src/AtomUI.Base/MotionScene/IMotion.cs +++ b/src/AtomUI.Base/MotionScene/IMotion.cs @@ -5,13 +5,13 @@ using Avalonia.Animation.Easings; namespace AtomUI.MotionScene; -internal enum MotionSpiritType +public enum MotionSpiritType { Animation, Transition } -internal interface IMotion +public interface IMotion { RelativePoint RenderTransformOrigin { get; } IList Animations { get; } diff --git a/src/AtomUI.Base/MotionScene/MoveMotions.cs b/src/AtomUI.Base/MotionScene/MoveMotions.cs index 10fbc3eeb..f5594f8fc 100644 --- a/src/AtomUI.Base/MotionScene/MoveMotions.cs +++ b/src/AtomUI.Base/MotionScene/MoveMotions.cs @@ -10,7 +10,7 @@ internal class MoveDownInMotion : AbstractMotion public double Offset { get; } public MoveDownInMotion(double offset, - TimeSpan duration, + TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new QuinticEaseOut(), fillMode) @@ -111,7 +111,7 @@ internal class MoveDownOutMotion : AbstractMotion public double Offset { get; } public MoveDownOutMotion(double offset, - TimeSpan duration, + TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new QuinticEaseIn(), fillMode) @@ -202,7 +202,7 @@ internal class MoveUpInMotion : AbstractMotion public double Offset { get; } public MoveUpInMotion(double offset, - TimeSpan duration, + TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new QuinticEaseOut(), fillMode) @@ -303,7 +303,7 @@ internal class MoveUpOutMotion : AbstractMotion public double Offset { get; } public MoveUpOutMotion(double offset, - TimeSpan duration, + TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new QuinticEaseIn(), fillMode) @@ -396,7 +396,7 @@ internal class MoveLeftInMotion : AbstractMotion public double Offset { get; } public MoveLeftInMotion(double offset, - TimeSpan duration, + TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new QuinticEaseOut(), fillMode) @@ -500,7 +500,7 @@ internal class MoveLeftOutMotion : AbstractMotion public double Offset { get; } public MoveLeftOutMotion(double offset, - TimeSpan duration, + TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new QuinticEaseIn(), fillMode) @@ -589,7 +589,7 @@ internal class MoveRightInMotion : AbstractMotion public double Offset { get; } public MoveRightInMotion(double offset, - TimeSpan duration, + TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new QuinticEaseOut(), fillMode) @@ -691,7 +691,7 @@ internal class MoveRightOutMotion : AbstractMotion public double Offset { get; } public MoveRightOutMotion(double offset, - TimeSpan duration, + TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new QuinticEaseIn(), fillMode) diff --git a/src/AtomUI.Base/MotionScene/SlideMotions.cs b/src/AtomUI.Base/MotionScene/SlideMotions.cs index 020555c95..a8dec08e0 100644 --- a/src/AtomUI.Base/MotionScene/SlideMotions.cs +++ b/src/AtomUI.Base/MotionScene/SlideMotions.cs @@ -7,7 +7,7 @@ namespace AtomUI.MotionScene; internal class SlideUpInMotion : AbstractMotion { - public SlideUpInMotion(TimeSpan duration, + public SlideUpInMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CubicEaseOut(), fillMode) @@ -35,7 +35,7 @@ internal class SlideUpInMotion : AbstractMotion internal class SlideUpOutMotion : AbstractMotion { - public SlideUpOutMotion(TimeSpan duration, + public SlideUpOutMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CubicEaseIn(), fillMode) @@ -63,7 +63,7 @@ internal class SlideUpOutMotion : AbstractMotion internal class SlideDownInMotion : AbstractMotion { - public SlideDownInMotion(TimeSpan duration, + public SlideDownInMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CubicEaseOut(), fillMode) @@ -91,7 +91,7 @@ internal class SlideDownInMotion : AbstractMotion internal class SlideDownOutMotion : AbstractMotion { - public SlideDownOutMotion(TimeSpan duration, + public SlideDownOutMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CubicEaseIn(), fillMode) @@ -119,7 +119,7 @@ internal class SlideDownOutMotion : AbstractMotion internal class SlideLeftInMotion : AbstractMotion { - public SlideLeftInMotion(TimeSpan duration, + public SlideLeftInMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CubicEaseOut(), fillMode) @@ -147,7 +147,7 @@ internal class SlideLeftInMotion : AbstractMotion internal class SlideLeftOutMotion : AbstractMotion { - public SlideLeftOutMotion(TimeSpan duration, + public SlideLeftOutMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CubicEaseIn(), fillMode) @@ -175,7 +175,7 @@ internal class SlideLeftOutMotion : AbstractMotion internal class SlideRightInMotion : AbstractMotion { - public SlideRightInMotion(TimeSpan duration, + public SlideRightInMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CubicEaseOut(), fillMode) @@ -203,7 +203,7 @@ internal class SlideRightInMotion : AbstractMotion internal class SlideRightOutMotion : AbstractMotion { - public SlideRightOutMotion(TimeSpan duration, + public SlideRightOutMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CubicEaseIn(), fillMode) diff --git a/src/AtomUI.Base/MotionScene/ZoomMotions.cs b/src/AtomUI.Base/MotionScene/ZoomMotions.cs index b9aa7581e..410b5dbdd 100644 --- a/src/AtomUI.Base/MotionScene/ZoomMotions.cs +++ b/src/AtomUI.Base/MotionScene/ZoomMotions.cs @@ -7,7 +7,7 @@ namespace AtomUI.MotionScene; internal class ZoomInMotion : AbstractMotion { - public ZoomInMotion(TimeSpan duration, + public ZoomInMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CircularEaseOut(), fillMode) @@ -35,7 +35,7 @@ internal class ZoomInMotion : AbstractMotion internal class ZoomOutMotion : AbstractMotion { - public ZoomOutMotion(TimeSpan duration, + public ZoomOutMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CircularEaseOut(), fillMode) @@ -69,7 +69,7 @@ internal class ZoomOutMotion : AbstractMotion internal class ZoomBigInMotion : AbstractMotion { - public ZoomBigInMotion(TimeSpan duration, + public ZoomBigInMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CircularEaseOut(), fillMode) @@ -97,7 +97,7 @@ internal class ZoomBigInMotion : AbstractMotion internal class ZoomBigOutMotion : AbstractMotion { - public ZoomBigOutMotion(TimeSpan duration, + public ZoomBigOutMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CircularEaseOut(), fillMode) @@ -131,7 +131,7 @@ internal class ZoomBigOutMotion : AbstractMotion internal class ZoomUpInMotion : AbstractMotion { - public ZoomUpInMotion(TimeSpan duration, + public ZoomUpInMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CircularEaseOut(), fillMode) @@ -159,7 +159,7 @@ internal class ZoomUpInMotion : AbstractMotion internal class ZoomUpOutMotion : AbstractMotion { - public ZoomUpOutMotion(TimeSpan duration, + public ZoomUpOutMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CircularEaseOut(), fillMode) @@ -193,7 +193,7 @@ internal class ZoomUpOutMotion : AbstractMotion internal class ZoomLeftInMotion : AbstractMotion { - public ZoomLeftInMotion(TimeSpan duration, + public ZoomLeftInMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CircularEaseOut(), fillMode) @@ -221,7 +221,7 @@ internal class ZoomLeftInMotion : AbstractMotion internal class ZoomLeftOutMotion : AbstractMotion { - public ZoomLeftOutMotion(TimeSpan duration, + public ZoomLeftOutMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CircularEaseOut(), fillMode) @@ -255,7 +255,7 @@ internal class ZoomLeftOutMotion : AbstractMotion internal class ZoomRightInMotion : AbstractMotion { - public ZoomRightInMotion(TimeSpan duration, + public ZoomRightInMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CircularEaseOut(), fillMode) @@ -283,7 +283,7 @@ internal class ZoomRightInMotion : AbstractMotion internal class ZoomRightOutMotion : AbstractMotion { - public ZoomRightOutMotion(TimeSpan duration, + public ZoomRightOutMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CircularEaseOut(), fillMode) @@ -317,7 +317,7 @@ internal class ZoomRightOutMotion : AbstractMotion internal class ZoomDownInMotion : AbstractMotion { - public ZoomDownInMotion(TimeSpan duration, + public ZoomDownInMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CircularEaseOut(), fillMode) @@ -345,7 +345,7 @@ internal class ZoomDownInMotion : AbstractMotion internal class ZoomDownOutMotion : AbstractMotion { - public ZoomDownOutMotion(TimeSpan duration, + public ZoomDownOutMotion(TimeSpan? duration = null, Easing? easing = null, FillMode fillMode = FillMode.Forward) : base(duration, easing ?? new CircularEaseOut(), fillMode) diff --git a/src/AtomUI.Controls/Flyouts/FlyoutHost.cs b/src/AtomUI.Controls/Flyouts/FlyoutHost.cs index f4dc486b3..722c9436c 100644 --- a/src/AtomUI.Controls/Flyouts/FlyoutHost.cs +++ b/src/AtomUI.Controls/Flyouts/FlyoutHost.cs @@ -1,6 +1,7 @@ using System.Reactive.Disposables; using AtomUI.Controls.Utils; using AtomUI.Data; +using AtomUI.MotionScene; using AtomUI.Theme; using AtomUI.Theme.Data; using AtomUI.Theme.Styling; @@ -62,8 +63,17 @@ public class FlyoutHost : Control, public static readonly StyledProperty PlacementGravityProperty = Popup.PlacementGravityProperty.AddOwner(); - public static readonly StyledProperty IsMotionEnabledProperty - = MotionAwareControlProperty.IsMotionEnabledProperty.AddOwner(); + public static readonly StyledProperty IsMotionEnabledProperty = + MotionAwareControlProperty.IsMotionEnabledProperty.AddOwner(); + + public static readonly StyledProperty MotionDurationProperty = + Popup.MotionDurationProperty.AddOwner(); + + public static readonly StyledProperty OpenMotionProperty = + Popup.OpenMotionProperty.AddOwner(); + + public static readonly StyledProperty CloseMotionProperty = + Popup.CloseMotionProperty.AddOwner(); /// /// 距离 anchor 的边距,根据垂直和水平进行设置 @@ -154,6 +164,24 @@ public class FlyoutHost : Control, get => GetValue(IsMotionEnabledProperty); set => SetValue(IsMotionEnabledProperty, value); } + + public TimeSpan MotionDuration + { + get => GetValue(MotionDurationProperty); + set => SetValue(MotionDurationProperty, value); + } + + public AbstractMotion? OpenMotion + { + get => GetValue(OpenMotionProperty); + set => SetValue(OpenMotionProperty, value); + } + + public AbstractMotion? CloseMotion + { + get => GetValue(CloseMotionProperty); + set => SetValue(CloseMotionProperty, value); + } #endregion @@ -212,6 +240,9 @@ public class FlyoutHost : Control, BindUtils.RelayBind(this, IsPointAtCenterProperty, Flyout, FlyoutControl.IsPointAtCenterProperty); BindUtils.RelayBind(this, MarginToAnchorProperty, Flyout, PopupFlyoutBase.MarginToAnchorProperty); BindUtils.RelayBind(this, IsMotionEnabledProperty, Flyout, PopupFlyoutBase.IsMotionEnabledProperty); + BindUtils.RelayBind(this, MotionDurationProperty, Flyout, PopupFlyoutBase.MotionDurationProperty); + BindUtils.RelayBind(this, OpenMotionProperty, Flyout, PopupFlyoutBase.OpenMotionProperty); + BindUtils.RelayBind(this, CloseMotionProperty, Flyout, PopupFlyoutBase.CloseMotionProperty); Flyout.IsDetectMouseClickEnabled = false; } } diff --git a/src/AtomUI.Controls/Flyouts/PopupFlyoutBase.cs b/src/AtomUI.Controls/Flyouts/PopupFlyoutBase.cs index b5cdb2e73..88f24ab18 100644 --- a/src/AtomUI.Controls/Flyouts/PopupFlyoutBase.cs +++ b/src/AtomUI.Controls/Flyouts/PopupFlyoutBase.cs @@ -1,6 +1,7 @@ using System.ComponentModel; using AtomUI.Controls.Utils; using AtomUI.Data; +using AtomUI.MotionScene; using AtomUI.Reflection; using Avalonia; using Avalonia.Controls; @@ -37,8 +38,7 @@ public class FlyoutPopupCreatedEventArgs : EventArgs /// /// 最基本得弹窗 Flyout,在这里不处理那种带箭头得 /// -public abstract class PopupFlyoutBase : FlyoutBase, - IPopupHostProvider +public abstract class PopupFlyoutBase : FlyoutBase, IPopupHostProvider { #region 公共属性定义 @@ -88,7 +88,17 @@ public abstract class PopupFlyoutBase : FlyoutBase, public static readonly StyledProperty PlacementConstraintAdjustmentProperty = Avalonia.Controls.Primitives.Popup.PlacementConstraintAdjustmentProperty.AddOwner(); - public static readonly StyledProperty IsMotionEnabledProperty = MotionAwareControlProperty.IsMotionEnabledProperty.AddOwner(); + public static readonly StyledProperty IsMotionEnabledProperty = + MotionAwareControlProperty.IsMotionEnabledProperty.AddOwner(); + + public static readonly StyledProperty MotionDurationProperty = + Popup.MotionDurationProperty.AddOwner(); + + public static readonly StyledProperty OpenMotionProperty = + Popup.OpenMotionProperty.AddOwner(); + + public static readonly StyledProperty CloseMotionProperty = + Popup.CloseMotionProperty.AddOwner(); public static readonly StyledProperty IsDetectMouseClickEnabledProperty = AvaloniaProperty.Register(nameof(IsDetectMouseClickEnabled), true); @@ -166,6 +176,24 @@ public abstract class PopupFlyoutBase : FlyoutBase, set => SetValue(IsMotionEnabledProperty, value); } + public TimeSpan MotionDuration + { + get => GetValue(MotionDurationProperty); + set => SetValue(MotionDurationProperty, value); + } + + public AbstractMotion? OpenMotion + { + get => GetValue(OpenMotionProperty); + set => SetValue(OpenMotionProperty, value); + } + + public AbstractMotion? CloseMotion + { + get => GetValue(CloseMotionProperty); + set => SetValue(CloseMotionProperty, value); + } + public bool IsDetectMouseClickEnabled { get => GetValue(IsDetectMouseClickEnabledProperty); @@ -214,6 +242,9 @@ public abstract class PopupFlyoutBase : FlyoutBase, BindUtils.RelayBind(this, MarginToAnchorProperty, popup); BindUtils.RelayBind(this, IsDetectMouseClickEnabledProperty, popup, Popup.IsDetectMouseClickEnabledProperty); BindUtils.RelayBind(this, IsMotionEnabledProperty, popup, Popup.IsMotionEnabledProperty); + BindUtils.RelayBind(this, MotionDurationProperty, popup, Popup.MotionDurationProperty); + BindUtils.RelayBind(this, OpenMotionProperty, popup, Popup.OpenMotionProperty); + BindUtils.RelayBind(this, CloseMotionProperty, popup, Popup.CloseMotionProperty); PopupCreated?.Invoke(this, new FlyoutPopupCreatedEventArgs(popup)); } diff --git a/src/AtomUI.Controls/Popup/Popup.cs b/src/AtomUI.Controls/Popup/Popup.cs index 0cfe7565a..c1e14e415 100644 --- a/src/AtomUI.Controls/Popup/Popup.cs +++ b/src/AtomUI.Controls/Popup/Popup.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using System.Reactive.Disposables; using AtomUI.Data; +using AtomUI.MotionScene; using AtomUI.Theme; using AtomUI.Theme.Data; using AtomUI.Theme.Styling; @@ -36,19 +37,25 @@ public class Popup : AvaloniaPopup, public static readonly StyledProperty MarginToAnchorProperty = AvaloniaProperty.Register(nameof(MarginToAnchor), 4); - public static readonly StyledProperty MotionDurationProperty - = AvaloniaProperty.Register(nameof(MotionDuration)); + public static readonly StyledProperty MotionDurationProperty = + AvaloniaProperty.Register(nameof(MotionDuration), TimeSpan.Zero); + + public static readonly StyledProperty OpenMotionProperty = + AvaloniaProperty.Register(nameof(OpenMotion)); + + public static readonly StyledProperty CloseMotionProperty = + AvaloniaProperty.Register(nameof(CloseMotion)); public static readonly DirectProperty IsFlippedProperty = AvaloniaProperty.RegisterDirect(nameof(IsFlipped), o => o.IsFlipped, (o, v) => o.IsFlipped = v); - public static readonly StyledProperty IsMotionEnabledProperty - = MotionAwareControlProperty.IsMotionEnabledProperty.AddOwner(); + public static readonly StyledProperty IsMotionEnabledProperty = + MotionAwareControlProperty.IsMotionEnabledProperty.AddOwner(); - public static readonly StyledProperty IsWaveSpiritEnabledProperty - = WaveSpiritAwareControlProperty.IsWaveSpiritEnabledProperty.AddOwner(); + public static readonly StyledProperty IsWaveSpiritEnabledProperty = + WaveSpiritAwareControlProperty.IsWaveSpiritEnabledProperty.AddOwner(); public BoxShadows MaskShadows { @@ -87,7 +94,18 @@ public class Popup : AvaloniaPopup, get => GetValue(IsWaveSpiritEnabledProperty); set => SetValue(IsWaveSpiritEnabledProperty, value); } + + public AbstractMotion? OpenMotion + { + get => GetValue(OpenMotionProperty); + set => SetValue(OpenMotionProperty, value); + } + public AbstractMotion? CloseMotion + { + get => GetValue(CloseMotionProperty); + set => SetValue(CloseMotionProperty, value); + } #endregion #region 内部属性定义 @@ -126,7 +144,6 @@ public class Popup : AvaloniaPopup, AffectsMeasure(PlacementProperty); AffectsMeasure(PlacementAnchorProperty); AffectsMeasure(PlacementGravityProperty); - IsLightDismissEnabledProperty.OverrideDefaultValue(false); } @@ -264,6 +281,8 @@ public class Popup : AvaloniaPopup, _buddyLayer = new PopupBuddyLayer(this, topLevel); BindUtils.RelayBind(this, MaskShadowsProperty, _buddyLayer, PopupBuddyLayer.MaskShadowsProperty); BindUtils.RelayBind(this, MotionDurationProperty, _buddyLayer, PopupBuddyLayer.MotionDurationProperty); + BindUtils.RelayBind(this, OpenMotionProperty, _buddyLayer, PopupBuddyLayer.OpenMotionProperty); + BindUtils.RelayBind(this, CloseMotionProperty, _buddyLayer, PopupBuddyLayer.CloseMotionProperty); } internal (bool, bool) CalculateFlipInfo(Size translatedSize, Rect anchorRect, PopupAnchor anchor, diff --git a/src/AtomUI.Controls/Popup/PopupBuddyLayer.cs b/src/AtomUI.Controls/Popup/PopupBuddyLayer.cs index 3f36ecf99..e37ff372e 100644 --- a/src/AtomUI.Controls/Popup/PopupBuddyLayer.cs +++ b/src/AtomUI.Controls/Popup/PopupBuddyLayer.cs @@ -20,6 +20,12 @@ internal class PopupBuddyLayer : SceneLayer, IPopupBuddyLayer, IShadowAwareLayer public static readonly StyledProperty MotionDurationProperty = Popup.MotionDurationProperty.AddOwner(); + public static readonly StyledProperty OpenMotionProperty = + Popup.OpenMotionProperty.AddOwner(); + + public static readonly StyledProperty CloseMotionProperty = + Popup.CloseMotionProperty.AddOwner(); + public BoxShadows MaskShadows { get => GetValue(MaskShadowsProperty); @@ -32,6 +38,18 @@ internal class PopupBuddyLayer : SceneLayer, IPopupBuddyLayer, IShadowAwareLayer set => SetValue(MotionDurationProperty, value); } + public AbstractMotion? OpenMotion + { + get => GetValue(OpenMotionProperty); + set => SetValue(OpenMotionProperty, value); + } + + public AbstractMotion? CloseMotion + { + get => GetValue(CloseMotionProperty); + set => SetValue(CloseMotionProperty, value); + } + #endregion private Popup _buddyPopup; @@ -177,7 +195,11 @@ internal class PopupBuddyLayer : SceneLayer, IPopupBuddyLayer, IShadowAwareLayer _buddyDecorator.Opacity = 0.0d; _buddyDecorator.NotifySceneShowed(); aboutToStart?.Invoke(); - var motion = new ZoomBigInMotion(MotionDuration); + var motion = OpenMotion ?? new ZoomBigInMotion(); + if (MotionDuration != TimeSpan.Zero) + { + motion.Duration = MotionDuration; + } NotifyAboutToRunAttachMotion(); motion.Run(_buddyDecorator, null, () => { @@ -190,7 +212,11 @@ internal class PopupBuddyLayer : SceneLayer, IPopupBuddyLayer, IShadowAwareLayer Action? completedAction = null) { aboutToStart?.Invoke(); - var motion = new ZoomBigOutMotion(MotionDuration); + var motion = CloseMotion ?? new ZoomBigOutMotion(); + if (MotionDuration != TimeSpan.Zero) + { + motion.Duration = MotionDuration; + } NotifyAboutToRunDetachMotion(); motion.Run(_buddyDecorator, null, () => {