From f9d67924347a158485b7bc7049fd8cfa084255e3 Mon Sep 17 00:00:00 2001 From: SyedAbdulAzeem Date: Wed, 10 Jun 2026 13:41:27 +0530 Subject: [PATCH 1/2] fix: CV2 CarouselView freezes with infinite loop when IsScrollAnimated=False on iOS --- .../Items2/iOS/CarouselViewController2.cs | 15 +++++ .../TestCases.HostApp/Issues/Issue35675.cs | 59 +++++++++++++++++++ .../Tests/Issues/Issue35675.cs | 27 +++++++++ 3 files changed, 101 insertions(+) create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue35675.cs create mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35675.cs diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs index 77368150476ac..0c3dc103e4767 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs @@ -19,6 +19,7 @@ public class CarouselViewController2 : ItemsViewController2 bool _isInternalCollectionUpdate = false; int _section = 0; bool _wasDetachedFromWindow = false; + int _gotoPosition = -1; CarouselViewLoopManager _carouselViewLoopManager; CancellationTokenSource _scrollDebounce; @@ -482,6 +483,7 @@ void ScrollToPosition(int goToPosition, int carouselPosition, bool animate, bool return; } + _gotoPosition = goToPosition; CollectionView.ScrollToItem(goToIndexPath, uICollectionViewScrollPosition, animate); } } @@ -509,6 +511,19 @@ internal void SetPosition(int position) return; } + if (_gotoPosition != -1) + { + if (position == _gotoPosition) + { + _gotoPosition = -1; + } + else + { + // Suppress intermediate positions while scrolling to target + return; + } + } + ItemsView.SetValueFromRenderer(CarouselView.PositionProperty, position); SetCurrentItem(position); UpdateVisualStates(); diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue35675.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue35675.cs new file mode 100644 index 0000000000000..c197bc277af43 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue35675.cs @@ -0,0 +1,59 @@ +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 35675, "[iOS] CarouselView freezes with infinite loop when IsScrollAnimated=False", PlatformAffected.iOS)] +public class Issue35675 : ContentPage +{ + readonly string[] _initialItems = ["Item 0", "Item 1", "Item 2"]; + readonly string[] _updatedItems = ["Item 0b", "Item 1b", "Item 2b"]; + + public Issue35675() + { + Label instructionLabel = new Label + { + AutomationId = "InstructionLabel", + Text = "The test passes if the CarouselView is not frozen after the button click and the current item is updated properly.", + HorizontalOptions = LayoutOptions.Center, + HorizontalTextAlignment = TextAlignment.Center, + FontSize = 18 + }; + + CarouselView carouselView = new CarouselView + { + AutomationId = "CarouselView", + HeightRequest = 300, + IsScrollAnimated = false, + BackgroundColor = Colors.LightGray, + HorizontalScrollBarVisibility = ScrollBarVisibility.Never, + ItemsSource = _initialItems, + ItemTemplate = new DataTemplate(() => + { + Label label = new Label + { + FontSize = 24 + }; + label.SetBinding(Label.TextProperty, "."); + label.SetBinding(Label.AutomationIdProperty, "."); + return label; + }) + }; + + Button scrollButton = new Button + { + Text = "Change Items And Scroll", + AutomationId = "ScrollButton" + }; + + scrollButton.Clicked += (s, e) => + { + carouselView.ItemsSource = _updatedItems; + carouselView.CurrentItem = "Item 2b"; + }; + + Content = new VerticalStackLayout + { + Padding = 20, + Spacing = 15, + Children = { instructionLabel, carouselView, scrollButton } + }; + } +} diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35675.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35675.cs new file mode 100644 index 0000000000000..b43f6b35fc815 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35675.cs @@ -0,0 +1,27 @@ +#if TEST_FAILS_ON_ANDROID && TEST_FAILS_ON_WINDOWS // Android Issue: https://github.com/dotnet/maui/issues/35643, Windows PR: https://github.com/dotnet/maui/pull/35398 +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue35675 : _IssuesUITest +{ + public Issue35675(TestDevice device) : base(device) + { + } + + public override string Issue => "[iOS] CarouselView freezes with infinite loop when IsScrollAnimated=False"; + + [Test] + [Category(UITestCategories.CarouselView)] + public void CV2DoesNotFreezeWhenSettingCurrentItemWithIsScrollAnimatedFalse() + { + App.WaitForElement("ScrollButton"); + App.WaitForElement("Item 0"); + App.Tap("ScrollButton"); + + App.WaitForElement("Item 2b"); + } +} +#endif From c4373b5e4ec0bd2ad7a2425f22f22d3dd0959214 Mon Sep 17 00:00:00 2001 From: SyedAbdulAzeem Date: Thu, 11 Jun 2026 21:40:20 +0530 Subject: [PATCH 2/2] fix: add missing _gotoPosition cleanup paths in CarouselViewController2 --- .../Core/Handlers/Items2/iOS/CarouselViewController2.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs index 0c3dc103e4767..ed5cf702e198f 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs @@ -334,7 +334,7 @@ void CollectionViewUpdated(object sender, NotifyCollectionChangedEventArgs e) return; } - //_gotoPosition = -1; + _gotoPosition = -1; // We need to update the position while modifying the collection. targetPosition = GetTargetPosition(); @@ -473,7 +473,7 @@ void ScrollToPosition(int goToPosition, int carouselPosition, bool animate, bool return; } - if (goToPosition != carouselPosition || forceScroll) + if (_gotoPosition == -1 && (goToPosition != carouselPosition || forceScroll)) { UICollectionViewScrollPosition uICollectionViewScrollPosition = IsHorizontal ? UICollectionViewScrollPosition.CenteredHorizontally : UICollectionViewScrollPosition.CenteredVertically; var goToIndexPath = GetScrollToIndexPath(goToPosition); @@ -567,6 +567,11 @@ internal void UpdateFromCurrentItem() return; } + if (currentItemIndex.Row == _gotoPosition) + { + _gotoPosition = -1; + } + ScrollToPosition(currentItemIndex.Row, carousel.Position, carousel.AnimateCurrentItemChanges); UpdateVisualStates();