Fix CollectionView.Header is header is not scrollable in Android platform#31661
Fix CollectionView.Header is header is not scrollable in Android platform#31661SuthiYuvaraj wants to merge 11 commits into
Conversation
|
Hey there @@SuthiYuvaraj! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
|
/azp run MAUI-UITests-public |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/rebase |
04fc615 to
d37685f
Compare
jsuarezruiz
left a comment
There was a problem hiding this comment.
@SuthiYuvaraj Could you rebase to fix the conflict?
d37685f to
9fbff30
Compare
🤖 AI Summary📊 Expand Full Review🔍 Pre-Flight — Context & Validation📝 Review Session — Create problems-report.html ·
|
| File:Line | Concern | Notes |
|---|---|---|
ItemContentView.cs |
IsHeaderOrFooterContent() called on every touch event (performance) |
Traverses logical parent tree on each touch |
ItemContentView.cs |
RequestDisallowInterceptTouchEvent(true) applied to ALL header/footer content on DOWN, not just scrollable |
Could affect non-scrollable headers |
ItemContentView.cs |
DispatchTouchEvent and OnInterceptTouchEvent become public API |
PublicAPI.Unshipped.txt updated, but are these appropriate as public API? |
ItemContentView.cs |
FindParentItemsView() traverses MAUI logical parent chain |
May not work with HeaderTemplate |
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #31661 | Override DispatchTouchEvent/OnInterceptTouchEvent in ItemContentView to call RequestDisallowInterceptTouchEvent for header/footer content | ⏳ PENDING (Gate) | ItemContentView.cs (+71), PublicAPI.Unshipped.txt (+2) |
Original PR |
🚦 Gate — Test Verification
📝 Review Session — Create problems-report.html · 05a9003
Result: ✅ PASSED
Platform: android
Mode: Full Verification
Test Filter: Issue22120
- Tests FAIL without fix ✅
- Tests PASS with fix ✅
The tests correctly catch the bug (CollectionView.Header not scrollable in Android) and confirm the PR's fix resolves it.
🔧 Fix — Analysis & Comparison
📝 Review Session — Create problems-report.html · 05a9003
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #31661 | Override DispatchTouchEvent/OnInterceptTouchEvent in ItemContentView to call RequestDisallowInterceptTouchEvent for header/footer content | ✅ PASS (Gate) | ItemContentView.cs (+71), PublicAPI.Unshipped.txt (+2) |
Original PR |
Exhausted: No (try-fix skipped due to rate limit errors on task agent - 429 Too Many Requests after 3 attempts)
Selected Fix: PR's fix - Gate confirmed tests pass. try-fix exploration blocked by environment rate limits.
📋 Report — Final Recommendation
📝 Review Session — Create problems-report.html · 05a9003
⚠️ Final Recommendation: REQUEST CHANGES
Summary
PR #31661 fixes Android-specific issue where CollectionView.Header containing scrollable content (e.g. ScrollView with ListView) was not scrollable due to RecyclerView intercepting all touch events. The fix uses RequestDisallowInterceptTouchEvent, which is the correct Android mechanism for nested scrolling. Gate verified tests fail without the fix and pass with it. However, several issues need to be addressed before merging.
Root Cause
Android's RecyclerView intercepts all touch events (via onInterceptTouchEvent) to handle its own scrolling, preventing nested scrollable views inside the header from receiving touch events. The fix overrides OnInterceptTouchEvent and DispatchTouchEvent in ItemContentView to call Parent?.RequestDisallowInterceptTouchEvent(true) on DOWN events for header/footer content, temporarily disabling RecyclerView's touch interception.
Fix Quality
The core approach (RequestDisallowInterceptTouchEvent) is the standard Android pattern for nested scrolling and is technically correct. However:
Issues Found
1. Unused Import (code quality)
using AndroidX.RecyclerView.Widget; // Added but never usedRecyclerView is imported but not referenced anywhere in the modified code. Should be removed.
2. HeaderTemplate Edge Case (functional limitation)
IsHeaderOrFooterContent() checks ReferenceEquals(View, structuredItemsView.Header). When HeaderTemplate is used instead of Header, structuredItemsView.Header returns null and the fix won't activate. This is an undocumented limitation that affects a common usage pattern. Should either be documented or handled.
3. Touch Event Logic Review
Setting RequestDisallowInterceptTouchEvent(true) unconditionally on DOWN for ALL header/footer content (not just when the content has scrollable children) is overly broad. A tap on a non-scrollable header button will also prevent RecyclerView from later receiving MOVE events until UP. While functionally correct (UP resets the flag), this is more aggressive than necessary and could potentially cause subtle interaction issues.
4. PR Is In DRAFT State
The PR is marked as draft. This may indicate the author is still working on it.
Test Coverage
Tests are well-structured:
Issue22120.cs(HostApp): Creates CollectionView with ScrollView header containing 15-item ListViewIssue22120.cs(SharedTests): Verifies scroll down and scroll up behavior with element visibility checks- Category:
UITestCategories.CollectionView✓ - Platform:
PlatformAffected.Android✓
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #31661 | Override DispatchTouchEvent/OnInterceptTouchEvent in ItemContentView to use RequestDisallowInterceptTouchEvent | ✅ PASS (Gate) | ItemContentView.cs (+71), PublicAPI.Unshipped.txt (+2) |
Original PR |
try-fix: Skipped due to environment rate limit (429 errors). PR's fix is the only validated candidate.
Changes Requested
- Remove unused import
using AndroidX.RecyclerView.Widget; - Document or fix
HeaderTemplatelimitation - add a comment or extend to handle templated headers - Mark PR as ready for review (remove draft status) when changes are complete
📋 Expand PR Finalization Review
Title: ✅ Good
Current: Fix CollectionView.Header is header is not scrollable in Android platform
Description: ⚠️ Needs Update
- Grammatical error: "is header is" (double "is")
- Missing platform prefix
[Android] - Verbose phrasing
✨ Suggested PR Description
[!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!
Root Cause
On Android, the RecyclerView that backs CollectionView intercepts all touch events to handle its own scrolling. When a scrollable control (e.g., ScrollView containing a ListView) is placed inside the CollectionView.Header or CollectionView.Footer, the RecyclerView consumes the touch events before they can reach the inner scrollable view, making the header/footer content unscrollable.
Description of Change
Added OnInterceptTouchEvent and DispatchTouchEvent overrides to ItemContentView (Android) to pass touch events through to scrollable header/footer content.
When the ItemContentView is rendering a header or footer (detected by comparing the logical view reference against StructuredItemsView.Header / StructuredItemsView.Footer):
OnInterceptTouchEvent(Down): CallsParent.RequestDisallowInterceptTouchEvent(true)to prevent the parentRecyclerViewfrom stealing touch events, then returnsfalseso child views can handle the gesture.DispatchTouchEvent(Up/Cancel): CallsParent.RequestDisallowInterceptTouchEvent(false)to restore normalRecyclerViewtouch interception after the gesture ends.
This is the standard Android nested scrolling pattern. Regular CollectionView items are unaffected — the overrides are no-ops when IsHeaderOrFooterContent() returns false.
Note: This fix applies when Header/Footer is set directly as a View. If HeaderTemplate/FooterTemplate is used (DataTemplate), the fix does not apply because the ReferenceEquals check compares against the template object, not the inflated view.
Issues Fixed
Fixes #22120
Platforms Tested
- Android
- Windows
- iOS
- Mac
Code Review: ⚠️ Issues Found
Code Review – PR #31661
🔴 Critical Issues
Unused using Directives
File: src/Controls/src/Core/Handlers/Items/Android/ItemContentView.cs
Problem: The PR adds two using directives that are not referenced anywhere in the new or existing code:
using AndroidX.Core.Widget; // unused
using AndroidX.RecyclerView.Widget; // unusedNeither NestedScrollView (from AndroidX.Core.Widget) nor RecyclerView (from AndroidX.RecyclerView.Widget) is referenced in the new logic. The IsHeaderOrFooterContent / FindParentItemsView methods work purely with MAUI logical types (IView, StructuredItemsView).
Recommendation: Remove both unused using directives before merge.
🟡 Suggestions
1. Fix Does Not Cover HeaderTemplate / FooterTemplate
File: src/Controls/src/Core/Handlers/Items/Android/ItemContentView.cs — IsHeaderOrFooterContent()
The ReferenceEquals check compares View (the MAUI virtual view) to structuredItemsView.Header:
return ReferenceEquals(View, structuredItemsView.Header) ||
ReferenceEquals(View, structuredItemsView.Footer);When Header / Footer is set directly as a View, this works correctly. However, when HeaderTemplate / FooterTemplate is used (a DataTemplate), structuredItemsView.Header holds the DataTemplate object, not the inflated view — so the check will always return false and the fix won't apply.
Recommendation: Either document this known limitation in a code comment and in the PR description, or extend the fix to handle the template case. At minimum, a // Note: Does not handle HeaderTemplate/FooterTemplate comment would prevent future confusion.
2. Extra Blank Line in DispatchTouchEvent
File: src/Controls/src/Core/Handlers/Items/Android/ItemContentView.cs
There is an extra blank line inside the outer if block:
public override bool DispatchTouchEvent(MotionEvent e)
{
if (IsHeaderOrFooterContent())
{
// ← extra blank line here
if (e.Action == MotionEventActions.Up || e.Action == MotionEventActions.Cancel)
{Recommendation: Remove the spurious blank line for consistency with the rest of the file's style.
✅ Looks Good
- Core fix logic is correct:
RequestDisallowInterceptTouchEvent(true)onMotionEventActions.Down/falseonUp/Cancelis the standard Android pattern for nested scroll containers and is widely used in the Android ecosystem. - Regular items unaffected:
IsHeaderOrFooterContent()returnsfalsefor non-header/footerItemContentViewinstances, so existing RecyclerView item behavior is unchanged. PublicAPI.Unshipped.txtupdated: Both new public overrides (DispatchTouchEvent,OnInterceptTouchEvent) are correctly added tonet-android/PublicAPI.Unshipped.txt.- UI test included:
Issue22120.cstests scroll-up and scroll-down on aScrollViewinsideCollectionView.Headerwith properAutomationIdattributes. The test uses[Category(UITestCategories.CollectionView)](single category, correct). - Logical tree traversal:
FindParentItemsView()traverses the MAUI logical parent chain (not the Android view hierarchy), which is the correct approach for finding the owningStructuredItemsView.
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 31661Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 31661" |
kubaflo
left a comment
There was a problem hiding this comment.
Could you please resolve conflicts?
|
/review -b feature/refactor-copilot-yml |
|
/review -b feature/refactor-copilot-yml -p android |
This comment has been minimized.
This comment has been minimized.
|
/review -b feature/enhanced-reviewer |
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 2 findings
See inline comments for details.
| if (itemsView is StructuredItemsView structuredItemsView) | ||
| { | ||
| // Check if our View is the same object reference as the header or footer | ||
| return ReferenceEquals(View, structuredItemsView.Header) || |
There was a problem hiding this comment.
[major] CollectionView Android - This only recognizes direct Header/Footer views. CreateHeaderFooterViewHolder also supports HeaderTemplate/FooterTemplate, where the realized View is created from the template and is not reference-equal to structuredItemsView.Header or .Footer, so templated scrollable headers/footers still allow the parent RecyclerView to steal the gesture. Consider tagging header/footer ItemContentViews when the adapter creates those holders instead of inferring it from the realized view reference.
| { | ||
| if (ev.Action == MotionEventActions.Down) | ||
| { | ||
| Parent?.RequestDisallowInterceptTouchEvent(true); |
There was a problem hiding this comment.
[major] Android Platform Specifics - Disallowing parent interception for the entire gesture means a drag that starts in a header/footer scroller cannot hand off to the outer CollectionView when the nested scroller is already at, or reaches, its top/bottom edge. The user-visible case is a scrollable header at its boundary: the same swipe should continue moving the collection, but the parent remains disallowed until Up/Cancel. Please scope this to actual scrollable-child handling, or release/re-evaluate once the nested target cannot scroll in the gesture direction.
|
/review -b feature/enhanced-reviewer -p android |
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@SuthiYuvaraj — new AI review results are available based on this last commit:
bd4a8d3.
Merge branch 'main' into fix-22120 To request a fresh review after new comments or commits, comment/review rerun.
Review Sessions — click to expand
Gate — Test Before & After Fix
Gate Result: ✅ PASSED
Platform: ANDROID · Base: main · Merge base: e904e900
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🖥️ Issue22120 Issue22120 |
✅ FAIL — 794s | ✅ PASS — 1320s |
🔴 Without fix — 🖥️ Issue22120: FAIL ✅ · 794s
Determining projects to restore...
Restored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 6.37 sec).
Restored /home/vsts/work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 6.31 sec).
Restored /home/vsts/work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 153 ms).
Restored /home/vsts/work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 12 ms).
Restored /home/vsts/work/1/s/src/Essentials/src/Essentials.csproj (in 24 ms).
Restored /home/vsts/work/1/s/src/Core/src/Core.csproj (in 41 ms).
Restored /home/vsts/work/1/s/src/Core/maps/src/Maps.csproj (in 26 ms).
Restored /home/vsts/work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 1.02 sec).
Restored /home/vsts/work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 33 ms).
Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 800 ms).
1 of 11 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
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.80-ci+azdo.14304655
Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
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.80-ci+azdo.14304655
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
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.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.80-ci+azdo.14304655
Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
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.80-ci+azdo.14304655
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
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.80-ci+azdo.14304655
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
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.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
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:34.68
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.02 sec).
Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 838 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/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 8.66 sec).
Restored /home/vsts/work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 6 ms).
Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 10 ms).
Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.Android.Tests/Controls.TestCases.Android.Tests.csproj (in 6.78 sec).
Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 2.07 sec).
5 of 13 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
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.80-ci+azdo.14304655
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
UITest.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
UITest.NUnit -> /home/vsts/work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.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.
[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.18] Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.67] 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
>>>>> 06/06/2026 22:11:34 FixtureSetup for Issue22120(Android)
>>>>> 06/06/2026 22:11:35 CollectionViewHeaderScrollViewIsScrollable Start
>>>>> 06/06/2026 22:11:50 CollectionViewHeaderScrollViewIsScrollable Stop
>>>>> 06/06/2026 22:11:50 Log types: logcat, bugreport, server
Failed CollectionViewHeaderScrollViewIsScrollable [16 s]
Error Message:
System.TimeoutException : Timed out waiting for element...
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.Issues.Issue22120.CollectionViewHeaderScrollViewIsScrollable() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue22120.cs:line 20
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
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue22120.trx
Total tests: 1
Failed: 1
Test Run Failed.
Total time: 1.8339 Minutes
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue22120.trx
🟢 With fix — 🖥️ Issue22120: PASS ✅ · 1320s
(truncated to last 15,000 chars)
rk/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 System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) [/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: --- End of stack trace from previous location --- [/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 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]
Build FAILED.
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: Mono.AndroidTools.InstallFailedException: Unexpected install output: cmd: Failure calling service package: Broken pipe (32) [/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: [/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 Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName) [/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 Mono.AndroidTools.AndroidDevice.<>c__DisplayClass105_0.<InstallPackage>b__0(Task`1 t) [/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 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/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: --- End of stack trace from previous location --- [/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 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/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 System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) [/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: --- End of stack trace from previous location --- [/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 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:07.97
* 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.80-ci+azdo.14304655
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
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.80-ci+azdo.14304655
Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
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.80-ci+azdo.14304655
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
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.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.80-ci+azdo.14304655
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.80-ci+azdo.14304655
Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
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.80-ci+azdo.14304655
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
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.80-ci+azdo.14304655
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
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:18.09
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.
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
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.80-ci+azdo.14304655
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14304655
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.80-ci+azdo.14304655
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.
[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.37] 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
>>>>> 06/06/2026 22:33:41 FixtureSetup for Issue22120(Android)
>>>>> 06/06/2026 22:33:41 CollectionViewHeaderScrollViewIsScrollable Start
>>>>> 06/06/2026 22:34:01 CollectionViewHeaderScrollViewIsScrollable Stop
Passed CollectionViewHeaderScrollViewIsScrollable [19 s]
NUnit Adapter 4.5.0.0: Test execution complete
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue22120.trx
Test Run Successful.
Total tests: 1
Passed: 1
Total time: 38.2434 Seconds
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue22120.trx
📁 Fix files reverted (3 files)
eng/pipelines/ci-copilot.ymlsrc/Controls/src/Core/Handlers/Items/Android/ItemContentView.cssrc/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt
UI Tests — CollectionView
Detected UI test categories: CollectionView
Pre-Flight — Context & Validation
Issue: #22120 - CollectionView.Header is not scrollable in Android platform
PR: #31661 - Android CollectionView header nested scrolling fix
Platforms Affected: Android
Files Changed: 2 implementation/API, 2 test (focused Android fix); broader checked-out branch also contains unrelated CI-agent files
Key Findings
- Remote PR/issue metadata could not be fetched because
ghis not authenticated; local checked-out PR branch and diff were used. - The PR fix adds touch interception overrides to
ItemContentViewand tests a directHeader = ScrollViewcase. - Supplied gate result: Gate ✅ PASSED — tests fail without the fix and pass with the PR fix. Gate was not re-run.
- Expert review found the PR approach does not cover
HeaderTemplate/FooterTemplate, traverses the MAUI logical tree on touch hot paths, and captures gestures that start on non-scrollable header/footer content.
Code Review Summary
Verdict: NEEDS_CHANGES
Confidence: medium
Errors: 1 | Warnings: 2 | Suggestions: 1
Key code review findings:
- ❌
ItemContentView.IsHeaderOrFooterContent()only detects directHeader/Footerviews; template-created header/footer views are not reference-equal toStructuredItemsView.Header/Footer. ⚠️ Touch handling does repeated logical-parent traversal inDispatchTouchEventandOnInterceptTouchEvent.⚠️ Parent intercept is disallowed for every header/footer DOWN, including non-scrollable header/footer content.- 💡 Prefer adapter item-type knowledge or an internal flag over public API-surfaced overrides and unused imports.
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #31661 | ItemContentView detects direct header/footer views by walking MAUI logical parents and disallows parent intercept on DOWN |
✅ PASSED (Gate) | ItemContentView.cs, PublicAPI, UI test files |
Original PR; gate supplied by caller |
Code Review — Deep Analysis
Code Review — PR #31661
Independent Assessment
What this changes: Adds Android touch-interception handling to ItemContentView so CollectionView header/footer content can receive nested scroll gestures, plus an Android UI test for a scrollable header.
Inferred motivation: A scrollable view placed in a CollectionView header cannot scroll because the parent RecyclerView intercepts the drag gesture.
Reconciliation with PR Narrative
Author claims: Remote PR narrative was unavailable because gh is not authenticated in this environment. Local issue/test names indicate the target bug is "CollectionView.Header is not scrollable in Android platform" (#22120).
Agreement/disagreement: The local diff addresses the direct Header = View case exercised by the test. Expert review found gaps for HeaderTemplate/FooterTemplate, hot-path tree walking, and overly broad gesture capture for non-scrollable header/footer content.
Findings
❌ Error — Template headers/footers are not covered
ItemContentView.IsHeaderOrFooterContent() compares the realized MAUI View with StructuredItemsView.Header/Footer. For HeaderTemplate/FooterTemplate, the realized View is the DataTemplate-created child while Header/Footer is the binding context object, so ReferenceEquals is false and the fix does not run for template-based headers/footers.
⚠️ Warning — Per-touch logical parent traversal in a hot path
DispatchTouchEvent and OnInterceptTouchEvent call IsHeaderOrFooterContent() for every event. Regular cells traverse the MAUI logical tree before returning false, adding repeated O(depth) work during touch/scroll paths.
⚠️ Warning — Header/footer gestures are captured even for non-scrollable content
Calling RequestDisallowInterceptTouchEvent(true) on every DOWN inside a header/footer prevents the RecyclerView from taking over a drag that starts on non-scrollable header/footer content.
💡 Suggestion — Remove unused imports/public API delta
The current implementation imports AndroidX namespaces that are not used and adds two public overrides to the Android public API list for behavior that could remain internal to existing handler classes.
Devil's Advocate
The direct-view header test passes with the PR fix according to the supplied gate result, and the Android pattern of disallowing parent intercept is established elsewhere (for example WebView). However, CollectionView header/footer creation has multiple adapter paths, and the current detection relies on MAUI logical parent identity rather than adapter knowledge, leaving real supported scenarios unhandled.
Verdict: NEEDS_CHANGES
Confidence: medium
Summary: The fix addresses the tested direct-header case but misses template-based header/footer content and adds hot-path overhead. Alternative candidates should move header/footer knowledge to adapter creation or RecyclerView interception, where the item type is authoritative.
Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix-1 | Adapter-set ItemContentView.IsHeaderOrFooter flag; O(1) touch check; covers direct and templated header/footer creation paths |
✅ PASS | 4 files | Better than PR for HeaderTemplate/FooterTemplate and hot-path cost; still broad for non-scrollable header content |
| 2 | try-fix-2 | MauiRecyclerView decides interception by child adapter item type (Header/Footer) and tracks the gesture |
✅ PASS | 3 files | Architecturally cleaner parent-layer fix; covers template/direct header/footer without ItemContentView API changes |
| PR | PR #31661 | ItemContentView walks MAUI logical parents on touch and compares realized view to StructuredItemsView.Header/Footer |
✅ PASSED (Gate) | 4 focused files | Original PR; gate supplied by caller |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| maui-expert-reviewer | 1 | Yes | Suggested adapter-set flag and RecyclerView item-type interception as materially different alternatives. |
| local loop | 2 | No | After two passing, materially distinct alternatives, remaining ideas are broader framework nested-scrolling changes or minor variations of the same gesture policy. |
Exhausted: Yes
Selected Fix: Candidate #2 — passes the targeted Android UI test, removes the PR's child-level logical-tree walk and ItemContentView public API additions, and uses the RecyclerView adapter item type as the authoritative header/footer signal. Candidate #1 is also viable and simpler if maintainers prefer localized ItemContentView changes.
Future Action — review latest findings
No alternative fix was selected for this run. Review the session findings and CI results before merging.
kubaflo
left a comment
There was a problem hiding this comment.
Could you please check the ai's suggestions?
|
/review rerun |
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 Description:
CollectionView.Header content is not scrollable on Android platform when it contains scrollable content like ScrollView with ListView.
Root Cause:
When the scrollable content is loaded inside the Header of the collectionview , touch is not passed to the internal scrollable control , which is handled by the TemplatedContentView in CollectionView.
Fix Description:
I have included the Touch Events in ItemContentView to handle the touch when the content is scrollable inside the header/ footer , Remaining cases it will not affects the previous behavior
Issues Fixed
Fixes #22120
Tested the behaviour in the following platforms
Output Screenshot
Before.mov
After.mov