Skip to content

[Android] Fix CollectionView EmptyView not displayed correctly#34956

Merged
kubaflo merged 3 commits into
dotnet:inflight/currentfrom
KarthikRajaKalaimani:fix-34861
Apr 17, 2026
Merged

[Android] Fix CollectionView EmptyView not displayed correctly#34956
kubaflo merged 3 commits into
dotnet:inflight/currentfrom
KarthikRajaKalaimani:fix-34861

Conversation

@KarthikRajaKalaimani

Copy link
Copy Markdown
Contributor

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:

  • Android
  • Windows
  • iOS
  • Mac

Reference:

N/A

Issues Fixed:

Fixes #34861

Screenshots

Before After
image

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34956

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34956"

@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label Apr 14, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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.

@dotnet-policy-service dotnet-policy-service Bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Apr 14, 2026
@sheiksyedm sheiksyedm marked this pull request as ready for review April 14, 2026 12:30
Copilot AI review requested due to automatic review settings April 14, 2026 12:30
@sheiksyedm sheiksyedm added platform/ios area-controls-collectionview CollectionView, CarouselView, IndicatorView labels Apr 14, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 treat EmptyViewAdapter items 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 EmptyView renders 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

Copilot AI Apr 14, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Suggested change
#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

Copilot uses AI. Check for mistakes.
@MauiBot

MauiBot commented Apr 15, 2026

Copy link
Copy Markdown
Collaborator

🚦 Gate — Test Before and After Fix

👋 @KarthikRajaKalaimani — new gate results are available. Please review the latest session below.

🚦 Gate Session9e3f22c · Commemt added · 2026-04-15 11:08 UTC

Gate Result: ⚠️ ENV ERROR

Platform: ANDROID · Base: main · Merge base: b43bdad1

Test Without Fix (expect FAIL) With Fix (expect PASS)
🖥️ Issue34861 Issue34861 ✅ FAIL — 901s ⚠️ ENV ERROR
🔴 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.yml
  • src/Controls/src/Core/Handlers/Items/Android/GridLayoutSpanSizeLookup.cs

@MauiBot

MauiBot commented Apr 15, 2026

Copy link
Copy Markdown
Collaborator

🤖 AI Summary

👋 @KarthikRajaKalaimani — new AI review results are available. Please review the latest session below.

📊 Review Session9e3f22c · Commemt added · 2026-04-15 12:09 UTC
🔍 Pre-Flight — Context & Validation

Issue: #34861 - [Android] CollectionView - EmptyView not displayed correctly
PR: #34956 - [Android] Fix CollectionView EmptyView not displayed correctly
Platforms Affected: Android only
Files Changed: 1 implementation, 2 test

Key Findings

  • When CollectionView uses GridItemsLayout (span > 1) with both a Header and EmptyView, the EmptyView renders beside the Header instead of below it
  • Root cause: GridLayoutSpanSizeLookup.GetSpanSize() relies on matching ItemViewType constants (Header=43, Footer=44), but EmptyViewAdapter uses private incrementing IDs starting from 1 — never matching those constants
  • When items list is empty, Android swaps in EmptyViewAdapter; its view types (1, 2, 3) all fall through to return 1 (single column), causing EmptyView and Header to share one row
  • PR fix: Add if (adapter is EmptyViewAdapter) return _gridItemsLayout.Span check at the top of GetSpanSize() — returns full span for all items when the collection is empty
  • Inline review comment (copilot-pull-request-reviewer): The #if TEST_FAILS_ON_IOS && TEST_FAILS_ON_WINDOWS && TEST_FAILS_ON_CATALYST guard is confusing; recommends #if ANDROID instead for clarity
    • However: The Android test project defines all three TEST_FAILS_ON_* symbols, so the guard is functionally correct (test compiles only for Android). It's a style concern, not a bug.
  • Gate result: ⚠️ ENV ERROR — test correctly FAILED without fix (proves test catches the bug), but ENV ERROR occurred when running WITH fix (infrastructure issue, not a code issue)

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #34956 Early-return full span when adapter is EmptyViewAdapter in GetSpanSize() ⚠️ ENV ERROR (Gate) 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() ⚠️ ENV ERROR (Gate) 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: ⚠️ ENV ERROR (infrastructure, not code)
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:

  1. Preprocessor guard is confusing — the test file uses #if TEST_FAILS_ON_IOS && TEST_FAILS_ON_WINDOWS && TEST_FAILS_ON_CATALYST which is counterintuitive (using "fails on other platforms" to imply "runs on Android"). A copilot reviewer already flagged this with a suggestion to use #if ANDROID instead. This is the standard pattern and clearer for future maintainers.

  2. Missing newline at end of test file — the test file Issue34861.cs in TestCases.Shared.Tests is 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
  • ⚠️ Couples GridLayoutSpanSizeLookup to 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

  1. src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34861.cs line 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
  2. 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 EmptyViewAdapter check if the team prefers no adapter type coupling in GridLayoutSpanSizeLookup
  • 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


@MauiBot MauiBot added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Apr 15, 2026
@kubaflo kubaflo changed the base branch from main to inflight/current April 17, 2026 09:19
@kubaflo kubaflo merged commit b349339 into dotnet:inflight/current Apr 17, 2026
44 of 46 checks passed
@github-actions github-actions Bot added this to the .NET 10 SR7 milestone Apr 17, 2026
devanathan-vaithiyanathan pushed a commit to Tamilarasan-Paranthaman/maui that referenced this pull request Apr 21, 2026
…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"> |
PureWeen pushed a commit that referenced this pull request Apr 22, 2026
<!-- 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"> |
PureWeen pushed a commit that referenced this pull request Apr 28, 2026
<!-- 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"> |
PureWeen pushed a commit that referenced this pull request Apr 29, 2026
<!-- 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"> |
github-actions Bot pushed a commit that referenced this pull request May 6, 2026
<!-- 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"> |
@github-actions github-actions Bot locked and limited conversation to collaborators May 17, 2026
@kubaflo kubaflo added the s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates label May 20, 2026
@PureWeen PureWeen modified the milestones: .NET 10 SR7, .NET 10 SR8 Jun 11, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-controls-collectionview CollectionView, CarouselView, IndicatorView community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/ios s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Android] CollectionView - EmptyView not displayed correctly

7 participants