fix.元素动画系统导致的调整组件闪现问题

This commit is contained in:
lincube
2026-06-02 16:31:29 +08:00
parent ed66869c8d
commit b12c9bf11d
4 changed files with 98 additions and 50 deletions

View File

@@ -35,4 +35,37 @@ public sealed class DesktopEditOverlayPresenterTests
Assert.Equal(180, ghost.Width);
Assert.Equal(120, ghost.Height);
}
[Fact]
public void CandidateRectUsesCanvasPlacement()
{
var presenter = new DesktopEditOverlayPresenter(new CompositionVisualAnimationService(_ => null));
var root = Assert.IsType<Canvas>(presenter.Root);
presenter.SetCandidateRect(new Rect(44, 58, 240, 160));
var candidate = root.Children.OfType<Border>().Single(child => child is not DesktopEditGhostView);
Assert.Equal(44, Canvas.GetLeft(candidate));
Assert.Equal(58, Canvas.GetTop(candidate));
Assert.Equal(240, candidate.Width);
Assert.Equal(160, candidate.Height);
}
[Fact]
public void ShowPreservesPreviewAndCandidateCanvasPlacement()
{
var presenter = new DesktopEditOverlayPresenter(new CompositionVisualAnimationService(_ => null));
var root = Assert.IsType<Canvas>(presenter.Root);
presenter.SetPreviewRect(new Rect(16, 32, 180, 120));
presenter.SetCandidateRect(new Rect(24, 40, 200, 140));
presenter.Show();
var ghost = root.Children.OfType<DesktopEditGhostView>().Single();
var candidate = root.Children.OfType<Border>().Single(child => child is not DesktopEditGhostView);
Assert.Equal(16, Canvas.GetLeft(ghost));
Assert.Equal(32, Canvas.GetTop(ghost));
Assert.Equal(24, Canvas.GetLeft(candidate));
Assert.Equal(40, Canvas.GetTop(candidate));
}
}

View File

@@ -0,0 +1,12 @@
using Avalonia;
using Avalonia.Threading;
namespace LanMountainDesktop.DesktopEditing;
internal static class DesktopEditAnimationRuntime
{
public static bool CanUseTransitions()
{
return Application.Current is not null && Dispatcher.UIThread.CheckAccess();
}
}

View File

@@ -52,7 +52,7 @@ internal sealed class DesktopEditGhostView : Border
ClipToBounds = true;
RenderTransformOrigin = new RelativePoint(0.5, 0.5, RelativeUnit.Relative);
RenderTransform = _scaleTransform;
if (Dispatcher.UIThread.CheckAccess())
if (DesktopEditAnimationRuntime.CanUseTransitions())
{
Transitions = new Transitions
{
@@ -301,6 +301,12 @@ internal sealed class DesktopEditGhostView : Border
internal void SetScaleTransitionDuration(TimeSpan duration)
{
if (!DesktopEditAnimationRuntime.CanUseTransitions())
{
_scaleTransform.Transitions = null;
return;
}
_scaleTransform.Transitions = new Transitions
{
CreateScaleTransition(ScaleTransform.ScaleXProperty, duration),
@@ -310,6 +316,12 @@ internal sealed class DesktopEditGhostView : Border
internal void SetOpacityTransitionDuration(TimeSpan duration)
{
if (!DesktopEditAnimationRuntime.CanUseTransitions())
{
Transitions = null;
return;
}
Transitions = new Transitions
{
CreateOpacityTransition(duration)

View File

@@ -33,8 +33,6 @@ internal sealed class DesktopEditOverlayPresenter
private Rect? _candidateRect;
private bool _isInvalid;
private bool _isVisible;
private bool _ghostUsesCompositionOffset;
private bool _candidateUsesCompositionOffset;
private int _dismissVersion;
private readonly SolidColorBrush _candidateBrush = new(Color.Parse("#FF0A84FF"));
@@ -68,7 +66,7 @@ internal sealed class DesktopEditOverlayPresenter
RenderTransformOrigin = new RelativePoint(0.5, 0.5, RelativeUnit.Relative),
RenderTransform = _candidateScale
};
if (Dispatcher.UIThread.CheckAccess())
if (DesktopEditAnimationRuntime.CanUseTransitions())
{
_candidateOutline.Transitions = new Transitions
{
@@ -102,7 +100,7 @@ internal sealed class DesktopEditOverlayPresenter
}
};
if (Dispatcher.UIThread.CheckAccess())
if (DesktopEditAnimationRuntime.CanUseTransitions())
{
_root.Transitions = new Transitions
{
@@ -170,21 +168,24 @@ internal sealed class DesktopEditOverlayPresenter
targetGhostScale = 1.03;
}
_root.Transitions = new Transitions
if (DesktopEditAnimationRuntime.CanUseTransitions())
{
CreateOpacityTransition(PickupDuration)
};
_ghostView.SetOpacityTransitionDuration(PickupDuration);
_ghostView.SetScaleTransitionDuration(PickupDuration);
_candidateScale.Transitions = new Transitions
{
CreateScaleTransition(ScaleTransform.ScaleXProperty, PickupDuration),
CreateScaleTransition(ScaleTransform.ScaleYProperty, PickupDuration)
};
_candidateOutline.Transitions = new Transitions
{
CreateOpacityTransition(PickupDuration)
};
_root.Transitions = new Transitions
{
CreateOpacityTransition(PickupDuration)
};
_ghostView.SetOpacityTransitionDuration(PickupDuration);
_ghostView.SetScaleTransitionDuration(PickupDuration);
_candidateScale.Transitions = new Transitions
{
CreateScaleTransition(ScaleTransform.ScaleXProperty, PickupDuration),
CreateScaleTransition(ScaleTransform.ScaleYProperty, PickupDuration)
};
_candidateOutline.Transitions = new Transitions
{
CreateOpacityTransition(PickupDuration)
};
}
_ghostView.SetRestingScale(initialGhostScale);
_candidateOutline.Opacity = 0;
_candidateScale.ScaleX = 0.97;
@@ -243,21 +244,24 @@ internal sealed class DesktopEditOverlayPresenter
var version = ++_dismissVersion;
_isVisible = false;
var settleDuration = isCancel ? CancelSettleDuration : CommitSettleDuration;
_root.Transitions = new Transitions
if (DesktopEditAnimationRuntime.CanUseTransitions())
{
CreateOpacityTransition(settleDuration)
};
_ghostView.SetOpacityTransitionDuration(settleDuration);
_ghostView.SetScaleTransitionDuration(settleDuration);
_candidateScale.Transitions = new Transitions
{
CreateScaleTransition(ScaleTransform.ScaleXProperty, settleDuration),
CreateScaleTransition(ScaleTransform.ScaleYProperty, settleDuration)
};
_candidateOutline.Transitions = new Transitions
{
CreateOpacityTransition(settleDuration)
};
_root.Transitions = new Transitions
{
CreateOpacityTransition(settleDuration)
};
_ghostView.SetOpacityTransitionDuration(settleDuration);
_ghostView.SetScaleTransitionDuration(settleDuration);
_candidateScale.Transitions = new Transitions
{
CreateScaleTransition(ScaleTransform.ScaleXProperty, settleDuration),
CreateScaleTransition(ScaleTransform.ScaleYProperty, settleDuration)
};
_candidateOutline.Transitions = new Transitions
{
CreateOpacityTransition(settleDuration)
};
}
var targetScale = _ghostView.HasPreviewImage
? 1.00
: isCancel ? 0.96 : 1.04;
@@ -292,7 +296,7 @@ internal sealed class DesktopEditOverlayPresenter
var rect = _previewRect.Value;
_ghostView.Width = Math.Max(1, rect.Width);
_ghostView.Height = Math.Max(1, rect.Height);
SetOverlayOffset(_ghostView, new Point(rect.X, rect.Y), ref _ghostUsesCompositionOffset);
SetOverlayOffset(_ghostView, new Point(rect.X, rect.Y));
_ghostView.UpdatePreviewMetrics(rect.Width, rect.Height);
}
@@ -309,7 +313,7 @@ internal sealed class DesktopEditOverlayPresenter
_candidateOutline.IsVisible = true;
_candidateOutline.Width = Math.Max(1, rect.Width);
_candidateOutline.Height = Math.Max(1, rect.Height);
SetOverlayOffset(_candidateOutline, new Point(rect.X, rect.Y), ref _candidateUsesCompositionOffset);
SetOverlayOffset(_candidateOutline, new Point(rect.X, rect.Y));
var cornerRadius = Math.Clamp(Math.Min(rect.Width, rect.Height) * 0.11, 14, 26);
_candidateOutline.CornerRadius = new CornerRadius(cornerRadius);
@@ -339,24 +343,11 @@ internal sealed class DesktopEditOverlayPresenter
return new Rect(rect.X, rect.Y, width, height);
}
private void SetOverlayOffset(Control target, Point position, ref bool usesCompositionOffset)
private void SetOverlayOffset(Control target, Point position)
{
if (_visualAnimationService.TrySetOffset(target, position))
{
Canvas.SetLeft(target, 0);
Canvas.SetTop(target, 0);
usesCompositionOffset = true;
return;
}
if (usesCompositionOffset)
{
_visualAnimationService.TryResetOffset(target);
usesCompositionOffset = false;
}
Canvas.SetLeft(target, position.X);
Canvas.SetTop(target, position.Y);
_visualAnimationService.TryResetOffset(target);
}
private static DoubleTransition CreateScaleTransition(AvaloniaProperty property, TimeSpan duration) =>