From 56f118d3a9d4c24b338f4d7b0ceab9d294e636c2 Mon Sep 17 00:00:00 2001 From: LuckyGeorge1975 <152692858+LuckyGeorge1975@users.noreply.github.com> Date: Thu, 8 Feb 2024 03:34:15 +0100 Subject: [PATCH] Fix: Enable seamless forward and backward transition in VirtualizingCarouselPanel (#14125) * Update VirtualizingCarouselPanel.cs Changes the calculation of the "forward" flag for the page transition to enable seamless forward and backward transitions. * Update VirtualizingCarouselPanel.cs Added Check for more than 2 items in carousel as there is actually no way to determine the correct transition with only 2 items. If there are only 2 items the transition behaviour is not changed. * Update VirtualizingCarouselPanelTests.cs Added Unit Tests for cycling through list forward and backward --- .../VirtualizingCarouselPanel.cs | 10 +++- .../VirtualizingCarouselPanelTests.cs | 49 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/VirtualizingCarouselPanel.cs b/src/Avalonia.Controls/VirtualizingCarouselPanel.cs index 958c19826d..d10ae124c1 100644 --- a/src/Avalonia.Controls/VirtualizingCarouselPanel.cs +++ b/src/Avalonia.Controls/VirtualizingCarouselPanel.cs @@ -158,7 +158,15 @@ namespace Avalonia.Controls GetTransition() is { } transition) { _transition = new CancellationTokenSource(); - transition.Start(_transitionFrom, to, _realizedIndex > _transitionFromIndex, _transition.Token) + + var forward = (_realizedIndex > _transitionFromIndex); + if (Items.Count > 2) + { + forward = forward || (_transitionFromIndex == Items.Count - 1 && _realizedIndex == 0); + forward = forward && !(_transitionFromIndex == 0 && _realizedIndex == Items.Count - 1); + } + + transition.Start(_transitionFrom, to, forward, _transition.Token) .ContinueWith(TransitionFinished, TaskScheduler.FromCurrentSynchronizationContext()); } diff --git a/tests/Avalonia.Controls.UnitTests/VirtualizingCarouselPanelTests.cs b/tests/Avalonia.Controls.UnitTests/VirtualizingCarouselPanelTests.cs index 5e276b5911..4f3b2f588f 100644 --- a/tests/Avalonia.Controls.UnitTests/VirtualizingCarouselPanelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/VirtualizingCarouselPanelTests.cs @@ -147,6 +147,55 @@ namespace Avalonia.Controls.UnitTests Times.Once); } + [Fact] + public void Changing_SelectedIndex_transitions_forward_cycle() + { + using var app = Start(); + var items = new Control[] { new Button(), new Canvas(), new Label() }; + var transition = new Mock(); + var (target, carousel) = CreateTarget(items, transition.Object); + var cycleindexes = new[] { 1, 2, 0}; + + for (int cycleIndex = 0; cycleIndex < cycleindexes.Length; cycleIndex++) + { + carousel.SelectedIndex = cycleindexes[cycleIndex]; + Layout(target); + + var index = cycleIndex; + transition.Verify(x => x.Start( + index > 0 ? items[cycleindexes[index - 1]] : items[0], + items[cycleindexes[index]], + true, + It.IsAny()), + Times.Once); + } + } + + [Fact] + public void Changing_SelectedIndex_transitions_backward_cycle() + { + using var app = Start(); + var items = new Control[] { new Button(), new Canvas(), new Label() }; + var transition = new Mock(); + var (target, carousel) = CreateTarget(items, transition.Object); + + var cycleindexes = new[] { 2, 1, 0}; + + for (int cycleIndex = 0; cycleIndex < cycleindexes.Length; cycleIndex++) + { + carousel.SelectedIndex = cycleindexes[cycleIndex]; + Layout(target); + + var index = cycleIndex; + transition.Verify(x => x.Start( + index > 0 ? items[cycleindexes[index - 1]] : items[0], + items[cycleindexes[index]], + false, + It.IsAny()), + Times.Once); + } + } + [Fact] public void TransitionFrom_Control_Is_Recycled_When_Transition_Completes() {