Refactor Popup motion

This commit is contained in:
chinboy
2025-02-27 15:10:06 +08:00
parent f890e4c614
commit f0cc45fe54
4 changed files with 35 additions and 75 deletions
+1 -23
View File
@@ -17,32 +17,11 @@ internal static class MotionInvoker
});
}
public static async Task InvokeAsync(MotionActorControl actor,
AbstractMotion motion,
Action? aboutToStart = null,
Action? completedAction = null,
CancellationToken cancellationToken = default)
{
await motion.RunAsync(actor, aboutToStart, completedAction, cancellationToken);
}
public static void InvokeInPopupLayer(SceneMotionActorControl actor,
AbstractMotion motion,
Action? aboutToStart = null,
Action? completedAction = null,
CancellationToken cancellationToken = default)
{
Dispatcher.UIThread.Invoke(async () =>
{
await InvokeInPopupLayerAsync(actor, motion, aboutToStart, completedAction, cancellationToken);
});
}
public static async Task InvokeInPopupLayerAsync(SceneMotionActorControl actor,
AbstractMotion motion,
Action? aboutToStart = null,
Action? completedAction = null,
CancellationToken cancellationToken = default)
{
var sceneLayer = PrepareSceneLayer(motion, actor);
var compositeDisposable = new CompositeDisposable();
@@ -59,10 +38,9 @@ internal static class MotionInvoker
actor.NotifySceneShowed();
actor.IsVisible = false;
await Dispatcher.UIThread.InvokeAsync(async () =>
Dispatcher.UIThread.InvokeAsync(async () =>
{
// 主要等待正常窗体显示出来再隐藏对话层,不然感觉会闪屏
await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken);
await motion.RunAsync(actor, aboutToStart, () =>
{
if (completedAction is not null)
+6 -8
View File
@@ -346,10 +346,12 @@ public class Flyout : PopupFlyoutBase
}
IsOpen = true;
Dispatcher.UIThread.InvokeAsync(async () =>
Dispatcher.UIThread.InvokeAsync(() =>
{
await Popup.OpenAsync();
HandlePopupOpened(placementTarget);
Popup.MotionAwareOpen(() =>
{
HandlePopupOpened(placementTarget);
});
});
return true;
}
@@ -375,11 +377,7 @@ public class Flyout : PopupFlyoutBase
}
IsOpen = false;
Dispatcher.UIThread.InvokeAsync(async () =>
{
await Popup.CloseAsync();
HandlePopupClosed();
});
Dispatcher.UIThread.InvokeAsync(() => { Popup.MotionAwareClose(HandlePopupClosed); });
return true;
}
+20 -32
View File
@@ -226,10 +226,7 @@ public class Popup : AvaloniaPopup,
{
if (popupHostProvider.PopupHost != pointerEventArgs.Root)
{
Dispatcher.UIThread.InvokeAsync(async () =>
{
await CloseAsync();
});
MotionAwareClose();
}
}
}
@@ -464,24 +461,20 @@ public class Popup : AvaloniaPopup,
};
}
public async Task OpenAsync()
public void MotionAwareOpen(Action? opened = null)
{
// AbstractPopup is currently open
if (IsOpen || _openAnimating || _closeAnimating)
{
await Task.CompletedTask;
return;
}
if (!IsMotionEnabled)
{
Open();
await Task.CompletedTask;
opened?.Invoke();
return;
}
_openAnimating = true;
var tsc = new TaskCompletionSource();
Open();
var popupRoot = Host as PopupRoot;
@@ -492,17 +485,14 @@ public class Popup : AvaloniaPopup,
Dispatcher.UIThread.Post(() =>
{
popupRoot.Opacity = 1.0;
RunOpenAnimation(popupRoot, tsc);
RunOpenAnimation(popupRoot, opened);
});
return;
}
else
{
RunOpenAnimation(popupRoot, tsc);
}
await tsc.Task;
RunOpenAnimation(popupRoot, opened);
}
private void RunOpenAnimation(PopupRoot popupRoot, TaskCompletionSource tsc)
private void RunOpenAnimation(PopupRoot popupRoot, Action? opened = null)
{
var placementTarget = GetEffectivePlacementTarget();
var popupOffset = popupRoot.PlatformImpl!.Position;
@@ -536,34 +526,34 @@ public class Popup : AvaloniaPopup,
{
_shadowLayer?.Open();
popupRoot.Show();
opened?.Invoke();
_isNeedWaitFlipSync = false;
_openAnimating = false;
_openAnimating = false;
if (RequestCloseWhereAnimationCompleted)
{
RequestCloseWhereAnimationCompleted = false;
Dispatcher.UIThread.InvokeAsync(async () => { await CloseAsync(); });
Dispatcher.UIThread.InvokeAsync(() => { Close(); });
}
tsc.SetResult();
});
});
}
public async Task CloseAsync()
public void MotionAwareClose(Action? closed = null)
{
if (_closeAnimating)
{
await Task.CompletedTask;
return;
}
if (_openAnimating)
{
RequestCloseWhereAnimationCompleted = true;
await Task.CompletedTask;
return;
}
if (!IsOpen)
{
await Task.CompletedTask;
return;
}
if (!IsMotionEnabled)
@@ -571,11 +561,11 @@ public class Popup : AvaloniaPopup,
_shadowLayer?.Close();
_isNeedDetectFlip = true;
Close();
await Task.CompletedTask;
closed?.Invoke();
return;
}
_closeAnimating = true;
var tsc = new TaskCompletionSource();
var motion = new ZoomBigOutMotion(MotionDuration);
@@ -600,22 +590,20 @@ public class Popup : AvaloniaPopup,
motionTarget.DesiredSize);
motionActor.SceneParent = topLevel;
Dispatcher.UIThread.Post(() =>
{
MotionInvoker.InvokeInPopupLayer(motionActor, motion, () =>
{
_shadowLayer?.Close();
popupRoot.Hide();
popupRoot.Opacity = 0;
}, () =>
{
_closeAnimating = false;
_isNeedDetectFlip = true;
Close();
tsc.SetResult();
closed?.Invoke();
});
});
await tsc.Task;
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+8 -12
View File
@@ -397,11 +397,8 @@ public class ToolTip : ContentControl,
{
TemplateApplied += DeferSetupArrowDecoratedBox;
}
Dispatcher.UIThread.InvokeAsync(async () =>
{
await _popup.OpenAsync();
});
_popup.MotionAwareOpen();
}
private void DeferSetupArrowDecoratedBox(object? sender, TemplateAppliedEventArgs args)
@@ -460,21 +457,20 @@ public class ToolTip : ContentControl,
var args = new RoutedEventArgs(ToolTipClosingEvent);
adornedControl.RaiseEvent(args);
}
Dispatcher.UIThread.InvokeAsync(async () =>
if (_popup is not null)
{
if (_popup is not null)
_popup.MotionAwareClose(() =>
{
await _popup.CloseAsync();
_popup.SetPopupParent(null);
_popup.PlacementTarget = null;
if (_popup is IPopupHostProvider popupHostProvider)
{
popupHostProvider.PopupHostChanged -= HandlePopupHostChanged;
}
}
_subscriptions?.Dispose();
});
_subscriptions?.Dispose();
});
}
}
private void SetToolTipColor(Control control)