feat(Flyout): add open/close motion and fix close animation being interrupted by HideCore cleanup

This commit is contained in:
chinboy
2026-04-30 11:21:07 +08:00
parent 6c9f47c87d
commit 3fdfd5af89
5 changed files with 55 additions and 4 deletions
@@ -49,6 +49,9 @@
</atom:FlyoutHost.Flyout>
<atom:Button ButtonType="Primary">Hover me</atom:Button>
</atom:FlyoutHost>
<atom:Button ButtonType="Primary"
atom:ToolTip.Tip="asdasdadsada">Tooltip me</atom:Button>
</StackPanel>
</Panel>
</atom:Window>
+22 -2
View File
@@ -1,4 +1,5 @@
using AtomUI.Controls;
using System.ComponentModel;
using AtomUI.Controls;
using AtomUI.Data;
using AtomUI.Desktop.Controls.DesignTokens;
using AtomUI.MotionScene;
@@ -200,11 +201,30 @@ public class Flyout : PopupFlyoutBase, IMotionAwareControl
popup.Opened += this.OnPopupOpened;
popup.Closed += this.OnPopupClosed;
popup.AddClosingEventHandler(this.OnPopupClosing);
popup.AddClosingEventHandler(HandlePopupClosing);
popup.KeyUp += this.OnPlacementTargetOrPopupKeyUp;
return popup;
}
private void HandlePopupClosing(object? sender, CancelEventArgs e)
{
if (!e.Cancel)
{
this.OnPopupClosing(sender, e);
}
}
protected override bool HideCore(bool canCancel = true)
{
if (canCancel && IsMotionEnabled && CloseMotion is not null && Popup.IsOpen)
{
Popup.IsOpen = false;
return true;
}
return base.HideCore(canCancel);
}
protected override Control CreatePresenter()
{
var presenter = new FlyoutPresenter();
@@ -235,6 +235,31 @@ public class FlyoutHost : ContentControl, IMotionAwareControl
_flyoutDisposables.Add(BindUtils.RelayBind(this, PopupRootShadowProperty, Flyout, FlyoutControl.PopupRootShadowProperty));
_flyoutDisposables.Add(BindUtils.RelayBind(this, OverlayHostShadowProperty, Flyout, FlyoutControl.OverlayHostShadowProperty));
_flyoutDisposables.Add(BindUtils.RelayBind(this, ShouldUseOverlayLayerProperty, Flyout, FlyoutControl.ShouldUseOverlayLayerProperty));
ConfigureMotion(Placement);
}
}
private void ConfigureMotion(PlacementMode placement)
{
if (!PopupUtils.IsCanonicalAnchorPlacementMode(placement))
{
OpenMotion = null;
CloseMotion = null;
}
else
{
var openMotion = new ZoomBigInMotion();
if (MotionDuration != TimeSpan.Zero)
{
openMotion.Duration = MotionDuration;
}
var closeMotion = new ZoomBigOutMotion();
if (MotionDuration != TimeSpan.Zero)
{
closeMotion.Duration = MotionDuration;
}
OpenMotion = openMotion;
CloseMotion = closeMotion;
}
}
@@ -250,6 +275,10 @@ public class FlyoutHost : ContentControl, IMotionAwareControl
SetupFlyoutProperties();
}
}
else if (change.Property == PlacementProperty)
{
ConfigureMotion(Placement);
}
}
}
@@ -308,7 +308,7 @@ internal class ShadowsAwareContainer : Decorator
{
if (child != null)
{
ConfigureShadowsInfo(child);
Dispatcher.Post(() => ConfigureShadowsInfo(child));
}
}
@@ -608,5 +608,4 @@ public class ToolTip : ContentControl,
}
}
}
}