From 9eed633e052aed20f8d2e96f308ef1fba85951f0 Mon Sep 17 00:00:00 2001 From: Lightczx <1686188646@qq.com> Date: Mon, 6 Nov 2023 15:52:50 +0800 Subject: [PATCH] DefaultItemCollectionTransitionProvider --- ...DefaultItemCollectionTransitionProvider.cs | 151 ++++++++++++++++++ .../Snap.Hutao/View/Page/CultivationPage.xaml | 10 +- 2 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 src/Snap.Hutao/Snap.Hutao/Control/Layout/DefaultItemCollectionTransitionProvider.cs diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Layout/DefaultItemCollectionTransitionProvider.cs b/src/Snap.Hutao/Snap.Hutao/Control/Layout/DefaultItemCollectionTransitionProvider.cs new file mode 100644 index 00000000..e10f2a65 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Control/Layout/DefaultItemCollectionTransitionProvider.cs @@ -0,0 +1,151 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.UI.Composition; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Hosting; +using System.Numerics; +using Windows.Foundation; + +namespace Snap.Hutao.Control.Layout; + +internal sealed class DefaultItemCollectionTransitionProvider : ItemCollectionTransitionProvider +{ + private const double DefaultAnimationDurationInMs = 300.0; + + static DefaultItemCollectionTransitionProvider() + { + AnimationSlowdownFactor = 1.0; + } + + public static double AnimationSlowdownFactor { get; set; } + + protected override bool ShouldAnimateCore(ItemCollectionTransition transition) + { + return true; + } + + protected override void StartTransitions(IList transitions) + { + List addTransitions = new(); + List removeTransitions = new(); + List moveTransitions = new(); + + foreach (ItemCollectionTransition transition in addTransitions) + { + switch (transition.Operation) + { + case ItemCollectionTransitionOperation.Add: + addTransitions.Add(transition); + break; + case ItemCollectionTransitionOperation.Remove: + removeTransitions.Add(transition); + break; + case ItemCollectionTransitionOperation.Move: + moveTransitions.Add(transition); + break; + } + } + + StartAddTransitions(addTransitions, removeTransitions.Count > 0, moveTransitions.Count > 0); + StartRemoveTransitions(removeTransitions); + StartMoveTransitions(moveTransitions, removeTransitions.Count > 0); + } + + private static void StartAddTransitions(IList transitions, bool hasRemoveTransitions, bool hasMoveTransitions) + { + foreach (ItemCollectionTransition transition in transitions) + { + ItemCollectionTransitionProgress progress = transition.Start(); + Visual visual = ElementCompositionPreview.GetElementVisual(progress.Element); + Compositor compositor = visual.Compositor; + + ScalarKeyFrameAnimation fadeInAnimation = compositor.CreateScalarKeyFrameAnimation(); + fadeInAnimation.InsertKeyFrame(0.0f, 0.0f); + + if (hasMoveTransitions && hasRemoveTransitions) + { + fadeInAnimation.InsertKeyFrame(0.66f, 0.0f); + } + else if (hasMoveTransitions || hasRemoveTransitions) + { + fadeInAnimation.InsertKeyFrame(0.5f, 0.0f); + } + + fadeInAnimation.InsertKeyFrame(1.0f, 1.0f); + fadeInAnimation.Duration = TimeSpan.FromMilliseconds( + DefaultAnimationDurationInMs * ((hasRemoveTransitions ? 1 : 0) + (hasMoveTransitions ? 1 : 0) + 1) * AnimationSlowdownFactor); + + CompositionScopedBatch batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation); + visual.StartAnimation("Opacity", fadeInAnimation); + batch.End(); + batch.Completed += (_, _) => progress.Complete(); + } + } + + private static void StartRemoveTransitions(IList transitions) + { + foreach (ItemCollectionTransition transition in transitions) + { + ItemCollectionTransitionProgress progress = transition.Start(); + Visual visual = ElementCompositionPreview.GetElementVisual(progress.Element); + Compositor compositor = visual.Compositor; + + ScalarKeyFrameAnimation fadeOutAnimation = compositor.CreateScalarKeyFrameAnimation(); + fadeOutAnimation.InsertExpressionKeyFrame(0.0f, "this.CurrentValue"); + fadeOutAnimation.InsertKeyFrame(1.0f, 0.0f); + fadeOutAnimation.Duration = TimeSpan.FromMilliseconds(DefaultAnimationDurationInMs * AnimationSlowdownFactor); + + CompositionScopedBatch batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation); + visual.StartAnimation(nameof(Visual.Opacity), fadeOutAnimation); + batch.End(); + batch.Completed += (_, _) => + { + visual.Opacity = 1.0f; + progress.Complete(); + }; + } + } + + private static void StartMoveTransitions(IList transitions, bool hasRemoveAnimations) + { + foreach (ItemCollectionTransition transition in transitions) + { + ItemCollectionTransitionProgress progress = transition.Start(); + Visual visual = ElementCompositionPreview.GetElementVisual(progress.Element); + Compositor compositor = visual.Compositor; + CompositionScopedBatch batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation); + + // Animate offset. + if (transition.OldBounds.X != transition.NewBounds.X || + transition.OldBounds.Y != transition.NewBounds.Y) + { + AnimateOffset(visual, compositor, transition.OldBounds, transition.NewBounds, hasRemoveAnimations); + } + + batch.End(); + batch.Completed += (_, _) => progress.Complete(); + } + } + + private static void AnimateOffset(Visual visual, Compositor compositor, Rect oldBounds, Rect newBounds, bool hasRemoveAnimations) + { + Vector2KeyFrameAnimation offsetAnimation = compositor.CreateVector2KeyFrameAnimation(); + + offsetAnimation.SetVector2Parameter("delta", new Vector2( + (float)(oldBounds.X - newBounds.X), + (float)(oldBounds.Y - newBounds.Y))); + offsetAnimation.SetVector2Parameter("final", default); + offsetAnimation.InsertExpressionKeyFrame(0.0f, "this.CurrentValue + delta"); + if (hasRemoveAnimations) + { + offsetAnimation.InsertExpressionKeyFrame(0.5f, "delta"); + } + + offsetAnimation.InsertExpressionKeyFrame(1.0f, "final"); + offsetAnimation.Duration = TimeSpan.FromMilliseconds( + DefaultAnimationDurationInMs * ((hasRemoveAnimations ? 1 : 0) + 1) * AnimationSlowdownFactor); + + visual.StartAnimation("TransformMatrix._41_42", offsetAnimation); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml index 1510dc9e..92887710 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml @@ -278,18 +278,14 @@ ItemTemplate="{StaticResource CultivateEntryTemplate}" ItemsSource="{Binding CultivateEntries}" SelectionMode="None"> + + + -