From b208402dc4d7e472d01167e7cea407f84c12fd74 Mon Sep 17 00:00:00 2001 From: SyedAbdulAzeem Date: Tue, 21 Oct 2025 12:23:05 +0530 Subject: [PATCH 1/3] Fix for issue in CarouselViewHandler2 where setting ItemSpacing prevents CurrentItem from updating correctly --- .../src/Core/Handlers/Items2/iOS/LayoutFactory2.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs index 4f9df4314b92..4dfe466795be 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs @@ -343,7 +343,19 @@ public static UICollectionViewLayout CreateCarouselLayout( return; } - var page = (offset.X + sectionMargin) / (env.Container.ContentSize.Width - sectionMargin * 2); + // Calculate page index accounting for ItemSpacing + var itemSpacing = itemsView.ItemsLayout is LinearItemsLayout linearLayout ? linearLayout.ItemSpacing : 0; + double page; + if (isHorizontal) + { + var effectiveItemWidth = env.Container.ContentSize.Width - sectionMargin * 2 + itemSpacing; + page = (offset.X + sectionMargin) / effectiveItemWidth; + } + else + { + var effectiveItemHeight = env.Container.ContentSize.Height - sectionMargin * 2 + itemSpacing; + page = (offset.Y + sectionMargin) / effectiveItemHeight; + } if (Math.Abs(page % 1) > (double.Epsilon * 100) || cv2Controller.ItemsSource.ItemCount <= 0) { From 5dab21d680ffbcb49d5047a8f0cab22f350ad41a Mon Sep 17 00:00:00 2001 From: SyedAbdulAzeem Date: Tue, 21 Oct 2025 21:45:17 +0530 Subject: [PATCH 2/3] Modified the fix and Added test case --- .../Handlers/Items2/iOS/LayoutFactory2.cs | 14 +--- .../TestCases.HostApp/Issues/Issue32048.cs | 78 +++++++++++++++++++ .../Tests/Issues/Issue32048.cs | 30 +++++++ 3 files changed, 111 insertions(+), 11 deletions(-) create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue32048.cs create mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32048.cs diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs index 4dfe466795be..f9914ec58a55 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs @@ -345,17 +345,9 @@ public static UICollectionViewLayout CreateCarouselLayout( // Calculate page index accounting for ItemSpacing var itemSpacing = itemsView.ItemsLayout is LinearItemsLayout linearLayout ? linearLayout.ItemSpacing : 0; - double page; - if (isHorizontal) - { - var effectiveItemWidth = env.Container.ContentSize.Width - sectionMargin * 2 + itemSpacing; - page = (offset.X + sectionMargin) / effectiveItemWidth; - } - else - { - var effectiveItemHeight = env.Container.ContentSize.Height - sectionMargin * 2 + itemSpacing; - page = (offset.Y + sectionMargin) / effectiveItemHeight; - } + + var effectiveItemWidth = env.Container.ContentSize.Width - sectionMargin * 2 + itemSpacing; + double page = (offset.X + sectionMargin) / effectiveItemWidth; if (Math.Abs(page % 1) > (double.Epsilon * 100) || cv2Controller.ItemsSource.ItemCount <= 0) { diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue32048.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue32048.cs new file mode 100644 index 000000000000..d76183e5c825 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue32048.cs @@ -0,0 +1,78 @@ +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 32048, "CurrentItem does not update when ItemSpacing is set", PlatformAffected.iOS)] +public class Issue32048 : ContentPage +{ + CarouselView2 carouselView; + Label currentItemLabel; + string firstItem = "Baboon"; + + public Issue32048() + { + carouselView = new CarouselView2 + { + AutomationId = "CarouselViewWithItemSpacing", + HeightRequest = 400, + BackgroundColor = Colors.LightGray, + ItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Horizontal) + { + ItemSpacing = 10, + SnapPointsType = SnapPointsType.MandatorySingle, + }, + ItemTemplate = new DataTemplate(() => + { + Label label = new Label + { + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center + }; + label.SetBinding(Label.TextProperty, "."); + + return new Grid + { + Children = { label } + }; + }), + ItemsSource = new string[] + { + "Baboon", + "Capuchin Monkey", + "Blue Monkey", + "Squirrel Monkey", + "Golden Lion Tamarin" + } + }; + + carouselView.CurrentItemChanged += OnCurrentItemChanged; + + currentItemLabel = new Label + { + AutomationId = "Issue32048StatusLabel", + Text = "Failure" + }; + + Grid grid = new Grid + { + Padding = 25, + RowSpacing = 10, + RowDefinitions = + { + new RowDefinition(GridLength.Auto), + new RowDefinition(GridLength.Auto) + } + }; + + grid.Add(carouselView); + grid.Add(currentItemLabel, row: 1); + + Content = grid; + } + + void OnCurrentItemChanged(object sender, CurrentItemChangedEventArgs e) + { + if (e.CurrentItem is not null && e.CurrentItem.ToString() != firstItem) + { + currentItemLabel.Text = "Success"; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32048.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32048.cs new file mode 100644 index 000000000000..4c2f629aa245 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32048.cs @@ -0,0 +1,30 @@ +#if TEST_FAILS_ON_WINDOWS // Issue Link - https://github.com/dotnet/maui/issues/31670 +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue32048 : _IssuesUITest +{ + public Issue32048(TestDevice device) : base(device) + { + } + + public override string Issue => "CurrentItem does not update when ItemSpacing is set"; + + [Test] + [Category(UITestCategories.CarouselView)] + public void VerifyCurrentItemUpdatesWithItemSpacing() + { + App.WaitForElement("CarouselViewWithItemSpacing"); + App.ScrollRight("CarouselViewWithItemSpacing"); + +#if MACCATALYST + Thread.Sleep(1000); +#endif + var resultLabel = App.WaitForElement("Issue32048StatusLabel").GetText(); + Assert.That(resultLabel, Is.EqualTo("Success")); + } +} +#endif \ No newline at end of file From 6a473e3c0486870c72b856e4a7c1031d5115ff36 Mon Sep 17 00:00:00 2001 From: SyedAbdulAzeem Date: Wed, 22 Oct 2025 18:10:01 +0530 Subject: [PATCH 3/3] Added a guard to prevent invalid layout calculations when the effective item width is zero or negative --- src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs index f9914ec58a55..e0adc6cb4c39 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs @@ -347,6 +347,12 @@ public static UICollectionViewLayout CreateCarouselLayout( var itemSpacing = itemsView.ItemsLayout is LinearItemsLayout linearLayout ? linearLayout.ItemSpacing : 0; var effectiveItemWidth = env.Container.ContentSize.Width - sectionMargin * 2 + itemSpacing; + + if (effectiveItemWidth <= 0) + { + return; + } + double page = (offset.X + sectionMargin) / effectiveItemWidth; if (Math.Abs(page % 1) > (double.Epsilon * 100) || cv2Controller.ItemsSource.ItemCount <= 0)