[Android] Fix CollectionView EmptyView not displayed correctly#34956
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34956Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34956" |
|
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
Fixes an Android CollectionView/GridItemsLayout edge case where, when the list is empty and an EmptyView + Header are set, the EmptyView could be laid out beside the header instead of below it due to EmptyViewAdapter view-type handling.
Changes:
- Android: Update
GridLayoutSpanSizeLookup.GetSpanSize()to treatEmptyViewAdapteritems as full-span. - Tests: Add a new HostApp repro page for Issue 34861 (header + empty view + span=2).
- Tests: Add an Appium/NUnit UI test validating the
EmptyViewrenders below the header (Android-only execution).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/Controls/src/Core/Handlers/Items/Android/GridLayoutSpanSizeLookup.cs | Ensures EmptyViewAdapter items always occupy the full grid span to prevent side-by-side header/empty layout. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue34861.cs | Adds a minimal repro page for the scenario (Grid span > 1 with Header + EmptyView and no items). |
| src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34861.cs | Adds an Appium UI test that asserts EmptyView is positioned below the header (Android-only). |
| @@ -0,0 +1,34 @@ | |||
| #if TEST_FAILS_ON_IOS && TEST_FAILS_ON_WINDOWS && TEST_FAILS_ON_CATALYST // Test fails on iOS, Windows and Catalyst because of Header is not visible https://github.com/dotnet/maui/issues/34897 | |||
There was a problem hiding this comment.
The preprocessor guard here is effectively being used to make this test run only on Android. That intent would be clearer and less coupled to the test-runner projects’ custom TEST_FAILS_ON_* constants if it used the standard #if ANDROID platform symbol instead (and kept the note about excluding iOS/Windows/MacCatalyst in a comment or via runtime Assert.Ignore where appropriate).
| #if TEST_FAILS_ON_IOS && TEST_FAILS_ON_WINDOWS && TEST_FAILS_ON_CATALYST // Test fails on iOS, Windows and Catalyst because of Header is not visible https://github.com/dotnet/maui/issues/34897 | |
| #if ANDROID // Test fails on iOS, Windows and Catalyst because of Header is not visible https://github.com/dotnet/maui/issues/34897 |
🚦 Gate — Test Before and After Fix
🚦 Gate Session —
|
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🖥️ Issue34861 Issue34861 |
✅ FAIL — 901s |
🔴 Without fix — 🖥️ Issue34861: FAIL ✅ · 901s
Determining projects to restore...
Restored /home/vsts/work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 624 ms).
Restored /home/vsts/work/1/s/src/Essentials/src/Essentials.csproj (in 4.11 sec).
Restored /home/vsts/work/1/s/src/Core/src/Core.csproj (in 5.81 sec).
Restored /home/vsts/work/1/s/src/Core/maps/src/Maps.csproj (in 2.48 sec).
Restored /home/vsts/work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 44 ms).
Restored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 26 ms).
Restored /home/vsts/work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 28 ms).
Restored /home/vsts/work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 421 ms).
Restored /home/vsts/work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 1.33 sec).
Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 2.11 sec).
1 of 11 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:08:28.08
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Determining projects to restore...
Restored /home/vsts/work/1/s/src/TestUtils/src/VisualTestUtils/VisualTestUtils.csproj (in 1.04 sec).
Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 994 ms).
Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Core/UITest.Core.csproj (in 6 ms).
Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 2.49 sec).
Restored /home/vsts/work/1/s/src/TestUtils/src/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 7.37 sec).
Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 4.16 sec).
Restored /home/vsts/work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 9 ms).
Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.Android.Tests/Controls.TestCases.Android.Tests.csproj (in 2.63 sec).
5 of 13 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
UITest.Core -> /home/vsts/work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
UITest.NUnit -> /home/vsts/work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
UITest.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
VisualTestUtils.MagickNet -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
UITest.Analyzers -> /home/vsts/work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
Controls.TestCases.Android.Tests -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
/home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.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.22] Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.83] Discovered: Controls.TestCases.Android.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 04/15/2026 10:42:11 FixtureSetup for Issue34861(Android)
>>>>> 04/15/2026 10:42:14 EmptyViewShouldAppearBelowHeaderInGridLayout Start
>>>>> 04/15/2026 10:43:20 EmptyViewShouldAppearBelowHeaderInGridLayout Stop
>>>>> 04/15/2026 10:43:25 Log types: logcat, bugreport, server
>>>>> 04/15/2026 10:43:40 SaveUIDiagnosticInfo timed out — app may be unresponsive, skipping UI diagnostics
Failed EmptyViewShouldAppearBelowHeaderInGridLayout [1 m 25 s]
Error Message:
EmptyView should appear below the Header, not beside it
Assert.That(emptyViewRect.Y, Is.GreaterThanOrEqualTo(headerRect.Y + headerRect.Height))
Expected: greater than or equal to 334
But was: 209
Stack Trace:
at Microsoft.Maui.TestCases.Tests.Issues.Issue34861.EmptyViewShouldAppearBelowHeaderInGridLayout() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34861.cs:line 26
1) at Microsoft.Maui.TestCases.Tests.Issues.Issue34861.EmptyViewShouldAppearBelowHeaderInGridLayout() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34861.cs:line 26
Standard Error Messages:
>>>>> 04/15/2026 10:43:40 SaveUIDiagnosticInfo timed out — app may be unresponsive, skipping UI diagnostics
NUnit Adapter 4.5.0.0: Test execution complete
Total tests: 1
Failed: 1
Test Run Failed.
Total time: 3.2789 Minutes
🟢 With fix — 🖥️ Issue34861: ⚠️ ENV ERROR · 1466s
(truncated to last 15,000 chars)
ns.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at Xamarin.Android.Tasks.FastDeploy.RunInstall() [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
0 Warning(s)
1 Error(s)
Time Elapsed 00:11:23.69
* daemon not running; starting now at tcp:5037
* daemon started successfully
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:09:35.98
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Determining projects to restore...
All projects are up-to-date for restore.
Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.60-ci+azdo.13842627
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
UITest.Core -> /home/vsts/work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
UITest.NUnit -> /home/vsts/work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
VisualTestUtils.MagickNet -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
UITest.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
UITest.Analyzers -> /home/vsts/work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
Controls.TestCases.Android.Tests -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
/home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.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.12] Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.31] Discovered: Controls.TestCases.Android.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 04/15/2026 11:07:15 FixtureSetup for Issue34861(Android)
>>>>> 04/15/2026 11:07:30 The FixtureSetup threw an exception. Attempt 0/1.
Exception details: System.TimeoutException: [Android] CollectionView EmptyView not displayed correctly with GridItemsLayout span > 1
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
at Microsoft.Maui.TestCases.Tests._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 25
at Microsoft.Maui.TestCases.Tests.UITest.FixtureSetup() in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 576
>>>>> 04/15/2026 11:07:33 FixtureSetup for Issue34861(Android)
>>>>> 04/15/2026 11:07:49 The FixtureSetup threw an exception. Attempt 1/1.
Exception details: System.TimeoutException: [Android] CollectionView EmptyView not displayed correctly with GridItemsLayout span > 1
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
at Microsoft.Maui.TestCases.Tests._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 25
at Microsoft.Maui.TestCases.Tests.UITest.FixtureSetup() in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 576
>>>>> 04/15/2026 11:07:49 Log types: logcat, bugreport, server
>>>>> 04/15/2026 11:07:49 Log types: logcat, bugreport, server
Failed EmptyViewShouldAppearBelowHeaderInGridLayout [45 s]
Error Message:
OneTimeSetUp: System.TimeoutException : [Android] CollectionView EmptyView not displayed correctly with GridItemsLayout span > 1
Stack Trace:
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
at Microsoft.Maui.TestCases.Tests._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 25
at Microsoft.Maui.TestCases.Tests.UITest.FixtureSetup() in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 576
at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 221
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
Setup failed for test fixture Microsoft.Maui.TestCases.Tests.Issues.Issue34861(Android)
System.TimeoutException : [Android] CollectionView EmptyView not displayed correctly with GridItemsLayout span > 1
StackTrace: at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
at Microsoft.Maui.TestCases.Tests._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 25
at Microsoft.Maui.TestCases.Tests.UITest.FixtureSetup() in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 576
at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 221
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
NUnit Adapter 4.5.0.0: Test execution complete
Test Run Failed.
Total tests: 1
Failed: 1
Total time: 56.8283 Seconds
⚠️ Issues found
⚠️ Issue34861 with fix:Exception calling "Matches" with "2" argument(s): "Value cannot be null. (Parameter 'input')"
📁 Fix files reverted (2 files)
eng/pipelines/ci-copilot.ymlsrc/Controls/src/Core/Handlers/Items/Android/GridLayoutSpanSizeLookup.cs
🤖 AI Summary
📊 Review Session —
|
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #34956 | Early-return full span when adapter is EmptyViewAdapter in GetSpanSize() |
GridLayoutSpanSizeLookup.cs |
Clean, minimal fix at correct location |
🔧 Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #34956 | Early-return full span when adapter is EmptyViewAdapter in GetSpanSize() |
GridLayoutSpanSizeLookup.cs |
Clean, minimal fix at correct location | |
| 1 | try-fix (claude-opus-4.6) | Inverted logic: whitelist data items (TextItem/TemplatedItem) for span=1, everything else defaults to full span | ✅ PASS | GridLayoutSpanSizeLookup.cs |
More future-proof — doesn't need adapter type check |
| 2 | try-fix (claude-sonnet-4.6) | Interface contract: IFullSpanItems marker interface on EmptyViewAdapter; span lookup checks adapter is IFullSpanItems |
✅ PASS | GridLayoutSpanSizeLookup.cs, EmptyViewAdapter.cs, new IFullSpanItems.cs |
Decoupled design but adds complexity (new file + interface) |
| 3 | try-fix (gpt-5.3-codex) | Semantic view-type bucketing in EmptyViewAdapter (stable low-byte type + versioned high-byte), span lookup normalizes via modulo before full-span checks | ✅ PASS | GridLayoutSpanSizeLookup.cs, EmptyViewAdapter.cs |
Overly complex — modulo-based ID scheme adds technical debt |
| 4 | try-fix (gpt-5.4) | Make EmptyViewAdapter use static ItemViewType.Header/Footer constants so existing span logic works automatically | ✅ PASS | EmptyViewAdapter.cs |
Latent bug: _headerViewType += 1 increment on content-update breaks constants after first update |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| claude-opus-4.6 | 2 | Yes | Override OnAttachedToRecyclerView in EmptyViewAdapter to swap in a full-span SpanSizeLookup on the GridLayoutManager |
| gpt-5.3-codex | 2 | Yes | IGridSpanProvider interface with GetSpanSizeForPosition callback |
| claude-sonnet-4.6 | 2 | Yes | Fix EmptyViewAdapter to use stable fixed IDs + replace _viewType += 1 trick with pool.setMaxRecycledViews |
| gpt-5.4 | 2 | Yes | Swap to LinearLayoutManager when empty, restore GridLayoutManager when items return |
Exhausted: Yes (all models queried × 2 rounds; ideas are increasingly complex; core fix space fully explored)
Selected Fix: Attempt 1 (inverted whitelist) as strongest independent alternative — but PR's fix is also clean and valid
📋 Report — Final Recommendation
⚠️ Final Recommendation: REQUEST CHANGES
Phase Status
| Phase | Status | Notes |
|---|---|---|
| Pre-Flight | ✅ COMPLETE | Android-only bug, 1 fix file, 2 test files |
| Gate | ❌ FAILED | Without-fix: ✅ FAIL (correct). With-fix: |
| Try-Fix | ✅ COMPLETE | 4 attempts, 4 passing (3 unique valid alternatives + 1 with latent bug) |
| Report | ✅ COMPLETE |
Summary
PR #34956 fixes a real Android bug: CollectionView with GridItemsLayout (span > 1) and both a Header + EmptyView shows the EmptyView beside the Header instead of below it. The root cause is well-identified and the fix is logically correct. The Gate ENV ERROR was an infrastructure issue (not a code problem) — the test correctly failed before the fix was applied.
However, there are two actionable issues with the PR that warrant changes before merge:
-
Preprocessor guard is confusing — the test file uses
#if TEST_FAILS_ON_IOS && TEST_FAILS_ON_WINDOWS && TEST_FAILS_ON_CATALYSTwhich is counterintuitive (using "fails on other platforms" to imply "runs on Android"). A copilot reviewer already flagged this with a suggestion to use#if ANDROIDinstead. This is the standard pattern and clearer for future maintainers. -
Missing newline at end of test file — the test file
Issue34861.csinTestCases.Shared.Testsis missing a trailing newline (diff shows\\ No newline at end of file).
Root Cause
GridLayoutSpanSizeLookup.GetSpanSize() checks static ItemViewType constants (Header=43, Footer=44) to determine full-width span. When the collection is empty, Android uses EmptyViewAdapter which initializes private view type IDs as incrementing integers (1, 2, 3). These IDs never match the static constants, so all positions return span=1 (single column), causing header and empty view to share one grid row.
Fix Quality
PR's fix (if (adapter is EmptyViewAdapter) return _gridItemsLayout.Span):
- ✅ Correct and minimal — single file, 10 lines added
- ✅ Properly documented with inline comment explaining the why
⚠️ CouplesGridLayoutSpanSizeLookupto a specific concrete adapter class (type-coupling concern)- ✅ No behavioral change for non-empty collections
Best alternative found (Attempt 1 — inverted whitelist):
- if (itemViewType == ItemViewType.Header || itemViewType == ItemViewType.Footer
- || itemViewType == ItemViewType.GroupHeader || itemViewType == ItemViewType.GroupFooter)
- {
- return _gridItemsLayout.Span;
- }
- return 1;
+ if (itemViewType == ItemViewType.TextItem || itemViewType == ItemViewType.TemplatedItem)
+ {
+ return 1;
+ }
+ return _gridItemsLayout.Span;- ✅ Single file, comparable simplicity
- ✅ More future-proof: structural items automatically get full span without needing to enumerate them
- ✅ No adapter type-check needed
⚠️ Changes the default behavior for any unknown/future view types (they'd get full span instead of span=1)
The PR's fix is simpler and safer (no behavioral change for unknown types). The inverted whitelist is a valid architectural preference but carries a risk of giving unexpected full span to new view types if ItemViewType is extended.
Required Changes
-
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34861.csline 1:
Apply the copilot reviewer's suggestion:// Before: #if TEST_FAILS_ON_IOS && TEST_FAILS_ON_WINDOWS && TEST_FAILS_ON_CATALYST // Test fails on iOS, Windows and Catalyst because of Header is not visible https://github.com/dotnet/maui/issues/34897 // After: #if ANDROID // Test fails on iOS, Windows and Catalyst because of Header is not visible https://github.com/dotnet/maui/issues/34897
-
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34861.cs:
Add missing trailing newline at end of file.
Optional Improvements (Non-Blocking)
- Consider the inverted whitelist approach (Attempt 1) as an alternative to the
adapter is EmptyViewAdaptercheck if the team prefers no adapter type coupling inGridLayoutSpanSizeLookup - The PR's fix is acceptable as-is for the implementation file — the two test changes above are the only blockers
Selected Fix: PR's fix — after the two required test file corrections are applied
…t#34956) <!-- 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! ### Issue Details: When a CollectionView with a GridItemsLayout (span > 1) has both a Header and an EmptyView, the EmptyView appeared beside the Header instead of below it. ### Root Cause: The root cause is in GridLayoutSpanSizeLookup.GetSpanSize(), which determines how many grid columns each item should occupy. Normally it checks ItemViewType constants (like Header = 43, Footer = 44) to give those items full-width span. However, when the collection is empty, Android uses an EmptyViewAdapter that assigns its items private incrementing IDs (1, 2, 3…) which never match those constants — so everything falls through to return 1, giving each item only a single column. ### Description of Change: The fix adds a simple early check: if the current adapter is an EmptyViewAdapter, immediately return the full _gridItemsLayout.Span for every position, skipping the view-type matching entirely. This ensures that when the collection is empty, all items (header, empty view, footer) always span the full grid width and stack vertically as expected. **Tested the behavior in the following platforms:** - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Reference: N/A ### Issues Fixed: Fixes dotnet#34861 ### Screenshots | Before | After | |---------|--------| | <img src="https://github.com/user-attachments/assets/d1cea6d7-157d-4230-a13e-dc06241176db" Width="300" Height="600"> | <img alt="image" src="https://github.com/user-attachments/assets/653580a4-0c9c-4fc8-b0e2-2712261aa823" Width="300" Height="600"> |
<!-- 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! ### Issue Details: When a CollectionView with a GridItemsLayout (span > 1) has both a Header and an EmptyView, the EmptyView appeared beside the Header instead of below it. ### Root Cause: The root cause is in GridLayoutSpanSizeLookup.GetSpanSize(), which determines how many grid columns each item should occupy. Normally it checks ItemViewType constants (like Header = 43, Footer = 44) to give those items full-width span. However, when the collection is empty, Android uses an EmptyViewAdapter that assigns its items private incrementing IDs (1, 2, 3…) which never match those constants — so everything falls through to return 1, giving each item only a single column. ### Description of Change: The fix adds a simple early check: if the current adapter is an EmptyViewAdapter, immediately return the full _gridItemsLayout.Span for every position, skipping the view-type matching entirely. This ensures that when the collection is empty, all items (header, empty view, footer) always span the full grid width and stack vertically as expected. **Tested the behavior in the following platforms:** - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Reference: N/A ### Issues Fixed: Fixes #34861 ### Screenshots | Before | After | |---------|--------| | <img src="https://github.com/user-attachments/assets/d1cea6d7-157d-4230-a13e-dc06241176db" Width="300" Height="600"> | <img alt="image" src="https://github.com/user-attachments/assets/653580a4-0c9c-4fc8-b0e2-2712261aa823" Width="300" Height="600"> |
<!-- 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! ### Issue Details: When a CollectionView with a GridItemsLayout (span > 1) has both a Header and an EmptyView, the EmptyView appeared beside the Header instead of below it. ### Root Cause: The root cause is in GridLayoutSpanSizeLookup.GetSpanSize(), which determines how many grid columns each item should occupy. Normally it checks ItemViewType constants (like Header = 43, Footer = 44) to give those items full-width span. However, when the collection is empty, Android uses an EmptyViewAdapter that assigns its items private incrementing IDs (1, 2, 3…) which never match those constants — so everything falls through to return 1, giving each item only a single column. ### Description of Change: The fix adds a simple early check: if the current adapter is an EmptyViewAdapter, immediately return the full _gridItemsLayout.Span for every position, skipping the view-type matching entirely. This ensures that when the collection is empty, all items (header, empty view, footer) always span the full grid width and stack vertically as expected. **Tested the behavior in the following platforms:** - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Reference: N/A ### Issues Fixed: Fixes #34861 ### Screenshots | Before | After | |---------|--------| | <img src="https://github.com/user-attachments/assets/d1cea6d7-157d-4230-a13e-dc06241176db" Width="300" Height="600"> | <img alt="image" src="https://github.com/user-attachments/assets/653580a4-0c9c-4fc8-b0e2-2712261aa823" Width="300" Height="600"> |
<!-- 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! ### Issue Details: When a CollectionView with a GridItemsLayout (span > 1) has both a Header and an EmptyView, the EmptyView appeared beside the Header instead of below it. ### Root Cause: The root cause is in GridLayoutSpanSizeLookup.GetSpanSize(), which determines how many grid columns each item should occupy. Normally it checks ItemViewType constants (like Header = 43, Footer = 44) to give those items full-width span. However, when the collection is empty, Android uses an EmptyViewAdapter that assigns its items private incrementing IDs (1, 2, 3…) which never match those constants — so everything falls through to return 1, giving each item only a single column. ### Description of Change: The fix adds a simple early check: if the current adapter is an EmptyViewAdapter, immediately return the full _gridItemsLayout.Span for every position, skipping the view-type matching entirely. This ensures that when the collection is empty, all items (header, empty view, footer) always span the full grid width and stack vertically as expected. **Tested the behavior in the following platforms:** - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Reference: N/A ### Issues Fixed: Fixes #34861 ### Screenshots | Before | After | |---------|--------| | <img src="https://github.com/user-attachments/assets/d1cea6d7-157d-4230-a13e-dc06241176db" Width="300" Height="600"> | <img alt="image" src="https://github.com/user-attachments/assets/653580a4-0c9c-4fc8-b0e2-2712261aa823" Width="300" Height="600"> |
<!-- 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! ### Issue Details: When a CollectionView with a GridItemsLayout (span > 1) has both a Header and an EmptyView, the EmptyView appeared beside the Header instead of below it. ### Root Cause: The root cause is in GridLayoutSpanSizeLookup.GetSpanSize(), which determines how many grid columns each item should occupy. Normally it checks ItemViewType constants (like Header = 43, Footer = 44) to give those items full-width span. However, when the collection is empty, Android uses an EmptyViewAdapter that assigns its items private incrementing IDs (1, 2, 3…) which never match those constants — so everything falls through to return 1, giving each item only a single column. ### Description of Change: The fix adds a simple early check: if the current adapter is an EmptyViewAdapter, immediately return the full _gridItemsLayout.Span for every position, skipping the view-type matching entirely. This ensures that when the collection is empty, all items (header, empty view, footer) always span the full grid width and stack vertically as expected. **Tested the behavior in the following platforms:** - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Reference: N/A ### Issues Fixed: Fixes #34861 ### Screenshots | Before | After | |---------|--------| | <img src="https://github.com/user-attachments/assets/d1cea6d7-157d-4230-a13e-dc06241176db" Width="300" Height="600"> | <img alt="image" src="https://github.com/user-attachments/assets/653580a4-0c9c-4fc8-b0e2-2712261aa823" Width="300" Height="600"> |
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:
When a CollectionView with a GridItemsLayout (span > 1) has both a Header and an EmptyView, the EmptyView appeared beside the Header instead of below it.
Root Cause:
The root cause is in GridLayoutSpanSizeLookup.GetSpanSize(), which determines how many grid columns each item should occupy. Normally it checks ItemViewType constants (like Header = 43, Footer = 44) to give those items full-width span. However, when the collection is empty, Android uses an EmptyViewAdapter that assigns its items private incrementing IDs (1, 2, 3…) which never match those constants — so everything falls through to return 1, giving each item only a single column.
Description of Change:
The fix adds a simple early check: if the current adapter is an EmptyViewAdapter, immediately return the full _gridItemsLayout.Span for every position, skipping the view-type matching entirely. This ensures that when
the collection is empty, all items (header, empty view, footer) always span the full grid width and stack vertically as expected.
Tested the behavior in the following platforms:
Reference:
N/A
Issues Fixed:
Fixes #34861
Screenshots