[iOS, MacCatalyst] Fix CollectionView grid spacing updates for first row and column#34598
[iOS, MacCatalyst] Fix CollectionView grid spacing updates for first row and column#34598KarthikRajaKalaimani wants to merge 5 commits intodotnet:mainfrom
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34598Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34598" |
|
Hey there @@KarthikRajaKalaimani! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
There was a problem hiding this comment.
Pull request overview
This PR updates the iOS/MacCatalyst Items2 CollectionView compositional grid layout to ensure spacing changes at runtime correctly affect the first row/column in a grid.
Changes:
- Apply half-spacing via
NSCollectionLayoutItem.ContentInsetsto distribute inter-item spacing across items. - Set
group.InterItemSpacingto0and rely on item/section insets plussection.InterGroupSpacingto control spacing.
| var halfHorizontalSpacing = new NFloat(horizontalItemSpacing / 2d); | ||
| var halfVerticalSpacing = new NFloat(verticalItemSpacing / 2d); | ||
|
|
||
| if (scrollDirection == UICollectionViewScrollDirection.Vertical && horizontalItemSpacing > 0) | ||
| { | ||
| item.ContentInsets = new NSDirectionalEdgeInsets(0, halfHorizontalSpacing, 0, halfHorizontalSpacing); | ||
| } | ||
| else if (scrollDirection == UICollectionViewScrollDirection.Horizontal && verticalItemSpacing > 0) | ||
| { | ||
| item.ContentInsets = new NSDirectionalEdgeInsets(halfVerticalSpacing, 0, halfVerticalSpacing, 0); | ||
| } | ||
| // Each group of items (for grouped collections) has a size | ||
| var groupSize = NSCollectionLayoutSize.Create(groupWidth, groupHeight); | ||
|
|
||
| // Create the group | ||
| // If vertical list, we want the group to layout horizontally (eg: grid columns go left to right) | ||
| // for horizontal list, we want to lay grid rows out vertically | ||
| // For simple lists it doesn't matter so much since the items span the entire width or height | ||
| var group = scrollDirection == UICollectionViewScrollDirection.Vertical | ||
| ? NSCollectionLayoutGroup.CreateHorizontal(groupSize, item, columns) | ||
| : NSCollectionLayoutGroup.CreateVertical(groupSize, item, columns); | ||
|
|
||
| if (scrollDirection == UICollectionViewScrollDirection.Vertical) | ||
| group.InterItemSpacing = NSCollectionLayoutSpacing.CreateFixed(new NFloat(horizontalItemSpacing)); | ||
| else | ||
| group.InterItemSpacing = NSCollectionLayoutSpacing.CreateFixed(new NFloat(verticalItemSpacing)); | ||
|
|
||
| group.InterItemSpacing = NSCollectionLayoutSpacing.CreateFixed(0); | ||
| // Create our section layout | ||
| var section = NSCollectionLayoutSection.Create(group: group); | ||
|
|
||
| if (scrollDirection == UICollectionViewScrollDirection.Vertical) | ||
| { | ||
| section.InterGroupSpacing = new NFloat(verticalItemSpacing); | ||
| if (verticalItemSpacing > 0) | ||
| { | ||
| section.ContentInsets = new NSDirectionalEdgeInsets(halfVerticalSpacing, 0, halfVerticalSpacing, 0); | ||
| } | ||
| } | ||
| else | ||
| { | ||
| section.InterGroupSpacing = new NFloat(horizontalItemSpacing); | ||
| if (horizontalItemSpacing > 0) | ||
| { | ||
| section.ContentInsets = new NSDirectionalEdgeInsets(0, halfHorizontalSpacing, 0, halfHorizontalSpacing); | ||
| } |
There was a problem hiding this comment.
Using item/section ContentInsets to distribute spacing introduces outer padding around the grid (first/last row/column get half the spacing). GridItemsLayout’s HorizontalItemSpacing/VerticalItemSpacing are documented as spacing between items, and the previous implementation (group.InterItemSpacing/section.InterGroupSpacing) did not add edge spacing. Consider compensating for the half-insets (e.g., offset section insets negatively on the corresponding edges) so the requested spacing exists only between items, not between items and the CollectionView edges.
cf6db4a to
b20cab3
Compare
6e563dc to
00535e4
Compare
🚦 Gate - Test Before and After Fix📊 Expand Full Gate —
|
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🖥️ Issue34257 Issue34257 |
✅ FAIL — 199s | ✅ PASS — 85s |
🔴 Without fix — 🖥️ Issue34257: FAIL ✅ · 199s
Determining projects to restore...
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 1.5 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 1.5 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 8.52 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 8.67 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 8.68 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 8.68 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 8.67 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 8.69 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/maps/src/Maps.csproj (in 8.7 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 8.69 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 8.7 sec).
/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0-ios26.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0-ios26.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0-ios26.0/Microsoft.Maui.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Maps.dll
Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Controls.Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Maps.dll
Controls.Foldable -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Foldable.dll
Controls.Xaml -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Xaml.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Microsoft.AspNetCore.Components.WebView.Maui -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-ios26.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
Detected signing identity:
Code Signing Key: "" (-)
Provisioning Profile: "" () - no entitlements
Bundle Id: com.microsoft.maui.uitests
App Id: com.microsoft.maui.uitests
Controls.TestCases.HostApp -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-ios/iossimulator-arm64/Controls.TestCases.HostApp.dll
Optimizing assemblies for size may change the behavior of the app. Be sure to test after publishing. See: https://aka.ms/dotnet-illink
Optimizing assemblies for size. This process might take a while.
Build succeeded.
/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
1 Warning(s)
0 Error(s)
Time Elapsed 00:01:36.61
Determining projects to restore...
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Core/UITest.Core.csproj (in 1.05 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/VisualTestUtils/VisualTestUtils.csproj (in 1.05 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 1.05 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 1.08 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 1.19 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 1.31 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 1.55 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 1.56 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 1.57 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 1.73 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 1.7 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 2.32 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.iOS.Tests/Controls.TestCases.iOS.Tests.csproj (in 3.42 sec).
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
Controls.CustomAttributes -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
UITest.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
VisualTestUtils -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
UITest.NUnit -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
VisualTestUtils.MagickNet -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
UITest.Appium -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
UITest.Analyzers -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
Controls.TestCases.iOS.Tests -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
Test run for /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (arm64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
/Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.04] Discovering: Controls.TestCases.iOS.Tests
[xUnit.net 00:00:00.13] Discovered: Controls.TestCases.iOS.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
NUnit3TestExecutor discovered 2 of 2 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 3/30/2026 7:12:29 AM FixtureSetup for Issue34257(iOS)
>>>>> 3/30/2026 7:12:33 AM UpdatingHorizontalSpacingShouldResizeBothColumns Start
>>>>> 3/30/2026 7:12:34 AM UpdatingHorizontalSpacingShouldResizeBothColumns Stop
>>>>> 3/30/2026 7:12:34 AM Log types: syslog, crashlog, performance, safariConsole, safariNetwork, server
>>>>> 3/30/2026 7:12:34 AM UpdatingVerticalSpacingShouldResizeBothRows Start
Failed UpdatingHorizontalSpacingShouldResizeBothColumns [1 s]
Error Message:
Expected the first column to move
Assert.That(firstColumnBefore.X, Is.Not.EqualTo(firstColumnAfter.X))
Expected: not equal to 17
But was: 17
Stack Trace:
at Microsoft.Maui.TestCases.Tests.Issues.Issue34257.UpdatingHorizontalSpacingShouldResizeBothColumns() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34257.cs:line 24
1) at Microsoft.Maui.TestCases.Tests.Issues.Issue34257.UpdatingHorizontalSpacingShouldResizeBothColumns() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34257.cs:line 24
>>>>> 3/30/2026 7:12:35 AM UpdatingVerticalSpacingShouldResizeBothRows Stop
>>>>> 3/30/2026 7:12:35 AM Log types: syslog, crashlog, performance, safariConsole, safariNetwork, server
Failed UpdatingVerticalSpacingShouldResizeBothRows [1 s]
Error Message:
Expected the first row to move
Assert.That(firstColumnBefore.Y, Is.Not.EqualTo(firstColumnAfter.Y))
Expected: not equal to 227
But was: 227
Stack Trace:
at Microsoft.Maui.TestCases.Tests.Issues.Issue34257.UpdatingVerticalSpacingShouldResizeBothRows() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34257.cs:line 35
1) at Microsoft.Maui.TestCases.Tests.Issues.Issue34257.UpdatingVerticalSpacingShouldResizeBothRows() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34257.cs:line 35
NUnit Adapter 4.5.0.0: Test execution complete
Test Run Failed.
Total tests: 2
Failed: 2
Total time: 58.8042 Seconds
🟢 With fix — 🖥️ Issue34257: PASS ✅ · 85s
Determining projects to restore...
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 323 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 337 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 338 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 371 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 382 ms).
6 of 11 projects are up-to-date for restore.
/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0-ios26.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0-ios26.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0-ios26.0/Microsoft.Maui.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Maps.dll
Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Controls.Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Maps.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-ios26.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Foldable -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Foldable.dll
Controls.Xaml -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Xaml.dll
Detected signing identity:
Code Signing Key: "" (-)
Provisioning Profile: "" () - no entitlements
Bundle Id: com.microsoft.maui.uitests
App Id: com.microsoft.maui.uitests
Controls.TestCases.HostApp -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-ios/iossimulator-arm64/Controls.TestCases.HostApp.dll
Optimizing assemblies for size may change the behavior of the app. Be sure to test after publishing. See: https://aka.ms/dotnet-illink
Optimizing assemblies for size. This process might take a while.
Build succeeded.
/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
1 Warning(s)
0 Error(s)
Time Elapsed 00:00:43.01
Determining projects to restore...
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 344 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 356 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 353 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 364 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 381 ms).
8 of 13 projects are up-to-date for restore.
Controls.CustomAttributes -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13687627
Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
VisualTestUtils -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
UITest.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
UITest.NUnit -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
VisualTestUtils.MagickNet -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
UITest.Appium -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
UITest.Analyzers -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
Controls.TestCases.iOS.Tests -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
Test run for /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (arm64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
/Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.04] Discovering: Controls.TestCases.iOS.Tests
[xUnit.net 00:00:00.12] Discovered: Controls.TestCases.iOS.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
NUnit3TestExecutor discovered 2 of 2 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 3/30/2026 7:13:55 AM FixtureSetup for Issue34257(iOS)
>>>>> 3/30/2026 7:13:59 AM UpdatingHorizontalSpacingShouldResizeBothColumns Start
>>>>> 3/30/2026 7:14:00 AM UpdatingHorizontalSpacingShouldResizeBothColumns Stop
>>>>> 3/30/2026 7:14:00 AM UpdatingVerticalSpacingShouldResizeBothRows Start
Passed UpdatingHorizontalSpacingShouldResizeBothColumns [811 ms]
>>>>> 3/30/2026 7:14:01 AM UpdatingVerticalSpacingShouldResizeBothRows Stop
Passed UpdatingVerticalSpacingShouldResizeBothRows [1 s]
NUnit Adapter 4.5.0.0: Test execution complete
Test Run Successful.
Total tests: 2
Passed: 2
Total time: 17.8053 Seconds
📁 Fix files reverted (2 files)
eng/pipelines/ci-copilot.ymlsrc/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs
🤖 AI Summary📊 Expand Full Review —
|
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #34598 | Replace group.InterItemSpacing with item.ContentInsets (half-spacing) + section.ContentInsets |
✅ PASSED (Gate) | LayoutFactory2.cs |
Adds edge padding — see Copilot review comment |
🔧 Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix (claude-opus-4.6) | + (half-spacing each side), zero InterItemSpacing/InterGroupSpacing | PASS | LayoutFactory2.cs |
No outer edge cleanest semantics |
| 2 | try-fix (claude-sonnet-4.6) | (half-spacing) + absolute item widths computed from container + original InterItemSpacing | PASS | LayoutFactory2.cs |
More complex; absolute widths from environment |
| 3 | try-fix (gpt-5.3-codex) | NSCollectionLayoutSpacing.CreateFlexible for `group. FAIL |
LayoutFactory2.cs |
Flexible spacing alone insufficient | InterItemSpacing` |
| 4 | try-fix (gpt-5.4, gemini unavailable) | Force layout rebuild in handler on spacing FAIL | ItemsViewController2.cs |
Confirms layout IS rebuilt; bug is in LayoutFactory2 geometry | change |
| 5 | try-fix (claude-sonnet-4.6, cross-poll) | (half-spacing) + negative to cancel outer edge; only for same-direction spacing | PASS | LayoutFactory2.cs |
Partially addresses reviewer concern; still needs section.ContentInsets for vertical gap |
| PR | PR #34598 | (half-spacing) + + | PASSED (Gate) | LayoutFactory2.cs |
Adds outer edge padding to grid reviewer flagged |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| claude-opus-4.6 | 2 | Yes | NSCollectionLayoutGroup.CreateCustom with explicit CGRect frames |
| ran as Attempt 5 | |||
| gpt-5.3-codex | 2 | Yes | VisibleItemsInvalidationHandler post-process frames at runtime |
| gpt-5.4 | 2 | Yes | Explicit subitems array with asymmetric per-item insets |
| claude-opus-4.6 | 3 | NO NEW IDEAS | Design space well-covered |
| claude-sonnet-4.6 | 3 | CreateCustom (already noted round 2) | Same idea as round not materially new |
| gpt-5.3-codex | 3 | CreateCustom variation | Same concept as round more complex, no gain |
| gpt-5.4 | 3 | Explicit subitems variation | Variation of round 2 similar complexity |
Exhausted: round 3 produced no new distinct approaches; all models converging on already-noted ideasYes
Selected Fix: Attempt 1 ( Reasons: (1) no outer edge padding at all (cleanest semantics, fully matches HorizontalItemSpacing/VerticalItemSpacing documentation as between-item spacing only); (2) simplest conceptual change; (3) directly fixes the PR reviewer's concern without adding section.ContentInsets; (4) single consistent mechanism (EdgeSpacing) for both directions; (5) fewer lines than Attempt 5 which still requires section.ContentInsets for same-direction spacingEdgeSpacing)
📋 Report — Final Recommendation
⚠️ Final Recommendation: REQUEST CHANGES
Phase Status
| Phase | Status | Notes |
|---|---|---|
| Pre-Flight | ✅ COMPLETE | Issue #34257, iOS/MacCatalyst, 1 fix file + 2 test files |
| Gate | ✅ PASSED | iOS — both tests fail without fix, pass with fix |
| Try-Fix | ✅ COMPLETE | 5 attempts, 3 passing alternatives found |
| Report | ✅ COMPLETE |
Summary
PR #34598 correctly fixes the CollectionView grid spacing bug on iOS/MacCatalyst where only the 2nd column/row visually updates when HorizontalItemSpacing/VerticalItemSpacing changes at runtime. The gate passed and the tests are well-designed. However, the PR's implementation has a documented semantic issue flagged by the Copilot code reviewer, and Try-Fix exploration found a simpler alternative that avoids it. The recommendation is REQUEST CHANGES to adopt the better fix.
Additionally, the PR has active merge conflicts with main that must be resolved before merge.
Root Cause
CreateGridLayout in LayoutFactory2.cs (Items2 iOS/MacCatalyst path) used group.InterItemSpacing which only inserts gaps between items within a group. The first item in each group always starts at offset 0 relative to the group origin — it is never repositioned when spacing changes. Only subsequent items shift (receiving a gap before them), leaving the first column/row visually frozen at runtime spacing updates.
Fix Quality
PR's fix (item.ContentInsets + section.ContentInsets):
- ✅ Fixes the bug — gate passed
- ✅ Tests are well-structured with descriptive AutomationIds
⚠️ Semantic issue:section.ContentInsetsadds outer padding around the entire grid — first and last row/column get half the inter-item spacing between them and the CollectionView boundary.HorizontalItemSpacing/VerticalItemSpacingare documented as spacing between items only; edge items should not receive insets from this property.⚠️ This was explicitly flagged by the Copilot code reviewer in PR inline comments.⚠️ PR has merge conflicts withmain.
Better alternative found (Attempt 1 — item.EdgeSpacing + group.EdgeSpacing):
- ✅ Fixes the bug — tests pass
- ✅ No outer edge padding —
NSCollectionLayoutEdgeSpacingshifts the item/group frame position itself (outside the frame), so adjacent items' frames shift together symmetrically with no boundary accumulation - ✅ Simpler: sets
group.InterItemSpacing = 0andsection.InterGroupSpacing = 0, nosection.ContentInsetsneeded - ✅ Directly addresses the reviewer's concern without
section.ContentInsets - ✅ Single consistent mechanism for both cross-axis and scroll-axis spacing
Suggested fix diff for LayoutFactory2.cs:
+ var halfHorizontalSpacing = new NFloat(horizontalItemSpacing / 2d);
+ var halfVerticalSpacing = new NFloat(verticalItemSpacing / 2d);
+ var zeroSpacing = NSCollectionLayoutSpacing.CreateFixed(0);
+
+ if (scrollDirection == UICollectionViewScrollDirection.Vertical && horizontalItemSpacing > 0)
+ item.EdgeSpacing = NSCollectionLayoutEdgeSpacing.Create(
+ leading: NSCollectionLayoutSpacing.CreateFixed(halfHorizontalSpacing),
+ top: zeroSpacing,
+ trailing: NSCollectionLayoutSpacing.CreateFixed(halfHorizontalSpacing),
+ bottom: zeroSpacing);
+ else if (scrollDirection == UICollectionViewScrollDirection.Horizontal && verticalItemSpacing > 0)
+ item.EdgeSpacing = NSCollectionLayoutEdgeSpacing.Create(
+ leading: zeroSpacing,
+ top: NSCollectionLayoutSpacing.CreateFixed(halfVerticalSpacing),
+ trailing: zeroSpacing,
+ bottom: NSCollectionLayoutSpacing.CreateFixed(halfVerticalSpacing));
+
+ // ...after group creation:
+ group.InterItemSpacing = NSCollectionLayoutSpacing.CreateFixed(0);
+ if (scrollDirection == Vertical && verticalItemSpacing > 0)
+ group.EdgeSpacing = NSCollectionLayoutEdgeSpacing.Create(zeroSpacing,
+ NSCollectionLayoutSpacing.CreateFixed(halfVerticalSpacing), zeroSpacing,
+ NSCollectionLayoutSpacing.CreateFixed(halfVerticalSpacing));
+ else if (scrollDirection == Horizontal && horizontalItemSpacing > 0)
+ group.EdgeSpacing = NSCollectionLayoutEdgeSpacing.Create(
+ NSCollectionLayoutSpacing.CreateFixed(halfHorizontalSpacing), zeroSpacing,
+ NSCollectionLayoutSpacing.CreateFixed(halfHorizontalSpacing), zeroSpacing);
+
- if (scrollDirection == UICollectionViewScrollDirection.Vertical)
- group.InterItemSpacing = NSCollectionLayoutSpacing.CreateFixed(new NFloat(horizontalItemSpacing));
- else
- group.InterItemSpacing = NSCollectionLayoutSpacing.CreateFixed(new NFloat(verticalItemSpacing));
var section = NSCollectionLayoutSection.Create(group: group);
- if (scrollDirection == UICollectionViewScrollDirection.Vertical)
- section.InterGroupSpacing = new NFloat(verticalItemSpacing);
- else
- section.InterGroupSpacing = new NFloat(horizontalItemSpacing);
+ // (remove section.InterGroupSpacing — group.EdgeSpacing handles scroll-axis gaps)Test Assessment
- ✅
Issue34257.cs(HostApp): Well-structured C# page with AutomationIds, 4 items in 2-column grid, buttons to apply horizontal/vertical spacing separately - ✅
Issue34257.cs(SharedTests): Two focused tests — one for each spacing direction — using position comparison (X/Ychanged) rather than screenshot comparison (avoids flakiness) - ✅
[Category(UITestCategories.CollectionView)]— correct category - ✅ Inherits
_IssuesUITest, standard pattern - ✅
PlatformAffected.Android | PlatformAffected.iOS | PlatformAffected.macOS— but PR only fixes iOS/MacCatalyst (Items2 path). Android is unresolved (issue [MAUI] I2_Vertical grid for horizontal Item Spacing and Vertical Item Spacing - horizontally updating the spacing only applies to the second column #34257 affects it too).
Action Items for Author
- Resolve merge conflicts with
main - Replace spacing approach with
item.EdgeSpacing+group.EdgeSpacingto avoid outer edge padding (see diff above), or confirm with the reviewer whether thesection.ContentInsetsbehavior is acceptable - Android: Issue [MAUI] I2_Vertical grid for horizontal Item Spacing and Vertical Item Spacing - horizontally updating the spacing only applies to the second column #34257 is labeled
platform/android— consider noting in PR that Android fix is deferred or tracked separately (the PR currently only fixes iOS/MacCatalyst Items2 path) - Test for zero-spacing reset: Consider adding a test that verifies spacing resets to 0 after being non-zero (ensure content insets/edge spacing are cleared when spacing = 0)
|
|
3 similar comments
|
|
|
|
|
|
kubaflo
left a comment
There was a problem hiding this comment.
Could you resolve conflicts?
1180c94 to
ee00398
Compare
…net#34527) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! Horizontalspacing / Verticalspacing is not not applied to the first column in GridItemLayout using CollectionView on Android platform. The grid spacing was not being distributed symmetrically across the active layout implementations, so edge items did not fully participate when spacing changed at runtime. - On Android, the fix in MauiRecyclerView.cs changes how RecyclerView padding is handled for GridItemsLayout. Android was already using SpacingItemDecoration, which applies half-spacing on all four sides of each item. Previously, negative RecyclerView padding canceled that spacing at the control edges. The branch keeps that negative-padding behavior for non-grid layouts, but disables it for GridItemsLayout, allowing the grid’s half-spacing to remain visible at the outer perimeter. This makes the first row and first column visually respond when spacing changes, but it also changes the grid behavior from spacing only between items to spacing around the outside edges as well. **Tested the behavior in the following platforms:** - [x] Android - [x] Windows - [ ] iOS - [ ] Mac N/A Fixes dotnet#34257 | Before | After | |---------|--------| | <Video src="https://github.com/user-attachments/assets/578dda69-1d60-474c-a6d8-23b3f9d29a50" Width="300" Height="600"> | <Video src="https://github.com/user-attachments/assets/7f3826e6-5922-4b6f-a6b9-de581b7db6c3" Width="300" Height="600"> |
ee00398 to
0c4c8c3
Compare
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Issue Details:
Horizontalspacing / Verticalspacing is not not applied to the first column in GridItemLayout using CollectionView on iOS,Mac and Android platform.
Root Cause:
The grid spacing was not being distributed symmetrically across the active layout implementations, so edge items did not fully participate when spacing changed at runtime. On iOS and MacCatalyst, the active Items2 compositional layout path handled spacing in a way that visually created gaps but did not cause the first column and first row to update consistently with the rest of the grid.
Description of Change:
**Tested the behavior in the following platforms: **
Reference:
N/A
Issues Fixed:
Fixes #34257
Screenshots
Screen.Recording.2026-03-18.at.4.25.45.PM.mov
Screen.Recording.2026-03-18.at.4.21.12.PM.mov