[Android] CarouselView: Fix position jump when tapping non-Start aligned Entry - #34532
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34532Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34532" |
There was a problem hiding this comment.
Pull request overview
Fixes an Android CarouselView page-jump caused by focus/cursor-driven RecyclerView scrolling when tapping a non-Start-aligned Entry, and adds a UI test + repro page for issue #13323.
Changes:
- Override
MauiCarouselRecyclerViewfocus/rectangle scrolling APIs to suppress/cancel unintended horizontal scrolling. - Add a HostApp repro page (entries centered) and new Appium UI tests validating position stability (with/without
Loop). - Update Android PublicAPI baseline for the new overrides.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue13323.cs | Adds Appium UI tests asserting carousel position doesn’t jump after tapping a centered Entry. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue13323.cs | Adds a repro page with two CarouselViews (looping and non-looping) and centered Entry controls. |
| src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt | Records new Android public overrides in the API baseline. |
| src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs | Adds overrides to suppress rectangle scroll requests and cancel focus-driven settling scroll. |
kubaflo
left a comment
There was a problem hiding this comment.
Looks like the build is not working
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines successfully started running 2 pipeline(s). |
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
/review rerun |
This comment has been minimized.
This comment has been minimized.
…gned Entry (#34532) <!-- 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! ### Root Cause On Android, when an `Entry` inside a `CarouselView` receives focus, two independent `RecyclerView` mechanisms trigger unintended horizontal scrolls. First, `requestRectangleOnScreen()` is called to ensure the cursor is visible. For `Center` or `End` alignment, the cursor’s X position is greater than zero, so `RecyclerView` initiates a horizontal smooth scroll. With `Loop=True`, the large virtual item pool amplifies the scroll delta, often jumping to position 0. Second, `LinearLayoutManager.onRequestChildFocus()` also triggers a settling scroll on focus. This behavior is correct for lists but incorrect for a full-page pager like `CarouselView`, where items are never partially visible. `Start` alignment is unaffected because the cursor’s X position is zero, so no scroll is triggered. ### Description of Change In `MauiCarouselRecyclerView.cs`, two overrides were added. `RequestChildRectangleOnScreen` now returns `false` to suppress cursor-driven scroll requests. `RequestChildFocus` calls `base` to preserve normal focus, keyboard, and accessibility behavior, then calls `StopScroll()` to cancel the unintended scroll side-effect. Since `MauiCarouselRecyclerView` is used only by `CarouselView`, no conditional logic is required. The fix preserves expected focus behavior while preventing incorrect page jumps. ### Issues Fixed Fixes #13323 Tested the behaviour in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Screenshots | Before Issue Fix | After Issue Fix | |------------------|-----------------| | <video width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/0c35c184-c162-444e-98c2-afef1c48516b" /> | <video width="350" alt="withfix" src="https://github.com/user-attachments/assets/4e86e451-e0cc-4dad-be64-b3211b7d2326" /> | --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@praveenkumarkarunanithi — new AI review results are available based on this last commit:
116f4a7. 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: 4567a055
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🖥️ Issue13323 Issue13323 |
✅ FAIL — 947s | ✅ PASS — 916s |
🔴 Without fix — 🖥️ Issue13323: FAIL ✅ · 947s
Determining projects to restore...
Restored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 8.02 sec).
Restored /home/vsts/work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 7.92 sec).
Restored /home/vsts/work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 223 ms).
Restored /home/vsts/work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 8 ms).
Restored /home/vsts/work/1/s/src/Essentials/src/Essentials.csproj (in 14 ms).
Restored /home/vsts/work/1/s/src/Core/src/Core.csproj (in 39 ms).
Restored /home/vsts/work/1/s/src/Core/maps/src/Maps.csproj (in 23 ms).
Restored /home/vsts/work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 2.53 sec).
Restored /home/vsts/work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 31 ms).
Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 2.28 sec).
1 of 11 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
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.90-ci+azdo.14445927
Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
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.90-ci+azdo.14445927
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
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.90-ci+azdo.14445927
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.90-ci+azdo.14445927
Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
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.90-ci+azdo.14445927
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
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.90-ci+azdo.14445927
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.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.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:09:23.84
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.3 sec).
Restored /home/vsts/work/1/s/src/TestUtils/src/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 7.07 sec).
Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.Android.Tests/Controls.TestCases.Android.Tests.csproj (in 8.52 sec).
Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Core/UITest.Core.csproj (in 8 ms).
Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 3 ms).
Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 1.18 sec).
Restored /home/vsts/work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 5 ms).
Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 2.89 sec).
5 of 13 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
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.90-ci+azdo.14445927
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
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.90-ci+azdo.14445927
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
UITest.Core -> /home/vsts/work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
VisualTestUtils.MagickNet -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.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
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.
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 2 of 2 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 06/22/2026 12:55:33 FixtureSetup for Issue13323(Android)
>>>>> 06/22/2026 12:55:37 CarouselView_EntryTap_DoesNotChangePosition Start
>>>>> 06/22/2026 12:56:07 CarouselView_EntryTap_DoesNotChangePosition Stop
>>>>> 06/22/2026 12:56:14 Log types: logcat, bugreport, server
Failed CarouselView_EntryTap_DoesNotChangePosition [48 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.AppUITests.Issues.Issue13323.CarouselView_EntryTap_DoesNotChangePosition() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue13323.cs:line 18
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
>>>>> 06/22/2026 12:56:25 CarouselView_Loop_EntryTap_DoesNotChangePosition Start
>>>>> 06/22/2026 12:56:56 CarouselView_Loop_EntryTap_DoesNotChangePosition Stop
>>>>> 06/22/2026 12:57:03 Log types: logcat, bugreport, server
Failed CarouselView_Loop_EntryTap_DoesNotChangePosition [48 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.AppUITests.Issues.Issue13323.CarouselView_Loop_EntryTap_DoesNotChangePosition() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue13323.cs:line 42
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
[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.37] Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:01.12] Discovered: Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue13323.trx
Total tests: 2
Failed: 2
Test Run Failed.
Total time: 3.1799 Minutes
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue13323.trx
🟢 With fix — 🖥️ Issue13323: PASS ✅ · 916s
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
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.90-ci+azdo.14445927
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
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.90-ci+azdo.14445927
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
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.90-ci+azdo.14445927
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.90-ci+azdo.14445927
Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
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.90-ci+azdo.14445927
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.90-ci+azdo.14445927
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
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.90-ci+azdo.14445927
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.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:12:46.34
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.90-ci+azdo.14445927
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445927
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.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.90-ci+azdo.14445927
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.
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 2 of 2 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 06/22/2026 13:12:57 FixtureSetup for Issue13323(Android)
>>>>> 06/22/2026 13:12:58 CarouselView_EntryTap_DoesNotChangePosition Start
>>>>> 06/22/2026 13:13:10 CarouselView_EntryTap_DoesNotChangePosition Stop
Passed CarouselView_EntryTap_DoesNotChangePosition [11 s]
>>>>> 06/22/2026 13:13:10 CarouselView_Loop_EntryTap_DoesNotChangePosition Start
>>>>> 06/22/2026 13:13:15 CarouselView_Loop_EntryTap_DoesNotChangePosition Stop
Passed CarouselView_Loop_EntryTap_DoesNotChangePosition [5 s]
NUnit Adapter 4.5.0.0: Test execution complete
[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.13] Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.68] Discovered: Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue13323.trx
Test Run Successful.
Total tests: 2
Passed: 2
Total time: 35.5821 Seconds
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue13323.trx
📁 Fix files reverted (2 files)
src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cssrc/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt
📋 Pre-Flight — Context & Validation
Issue: #13323 - CarouselView on Android does not work if HorizontalTextAlignment in Entry is not Start
PR: #34532 - Android CarouselView Entry focus/rectangle scroll fix
Platforms Affected: Android
Files Changed: 2 implementation, 2 test
Key Findings
- Local branch
pr-review-34532contains PR #34532 as a squashed commit overorigin/main; GitHub CLI is unauthenticated, so PR body, linked issue body, comments, reviews, and CI checks could not be fetched. - Implementation changes Android
MauiCarouselRecyclerViewto suppress child rectangle scroll requests and cancel focus-driven scrolls started from an idle carousel. - Regression coverage adds an Android issue page and two CarouselView UI tests for
Loop=falseandLoop=truewith a center-alignedEntry. - Applicable test category:
CarouselView.
Code Review Summary
Verdict: NEEDS_DISCUSSION
Confidence: low
Errors: 0 | Warnings: 1 | Suggestions: 1
Key code review findings:
⚠️ src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:641—RequestChildFocusmay not catch asynchronously scheduled RecyclerView focus-scroll paths ifScrollStateremains idle immediately afterbase.RequestChildFocus; however, theRequestChildRectangleOnScreenoverride likely handles the primary Issue13323 path.- 💡
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue13323.cs:32— test uses inline#if ANDROIDinside test methods for keyboard wait; repo UI-test guidance prefers platform-specific behavior behind helpers. - CI status is undetermined because
ghis unauthenticated in this environment. Gate result was provided by the caller: Gate ✅ PASSED — tests fail without fix and pass with PR fix.
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #34532 | Override RequestChildRectangleOnScreen to return false, and override RequestChildFocus to call StopScroll() if a focus request starts scrolling from idle. |
✅ PASSED (Gate) | MauiCarouselRecyclerView.cs, Android PublicAPI.Unshipped.txt, UI test files |
Original PR |
🔬 Code Review — Deep Analysis
Code Review — PR #34532
Independent Assessment
What this changes: Android MauiCarouselRecyclerView gains two RecyclerView overrides: RequestChildRectangleOnScreen returns false, blocking child-initiated rectangle scroll requests such as EditText cursor positioning, and RequestChildFocus calls base.RequestChildFocus then calls StopScroll() if the carousel transitioned from idle to scrolling due to the focus event. Public API entries are registered. Two UI tests cover Loop=false and Loop=true.
Inferred motivation: CarouselView on Android unexpectedly scrolls to a different page when an embedded center-aligned Entry is tapped. RecyclerView's default child focus/rectangle behavior tries to bring the focused child or cursor rectangle into view, which is wrong for a pager-style CarouselView that owns its page position.
Reconciliation with PR Narrative
Author claims: GitHub CLI authentication is unavailable in this environment, so the PR body and linked issue text could not be fetched.
Agreement/disagreement: The local diff is consistent with the inferred issue: the fix targets Android RecyclerView child focus and rectangle-scroll paths, and the tests exercise tapping a center-aligned Entry without changing CarouselView position.
Prior Review Reconciliation
| Prior ❌ Error Finding | Source | Status | Evidence |
|---|---|---|---|
| (unavailable) | GitHub review/comment surfaces | 🔄 Cannot verify | gh is unauthenticated (gh auth login required), so top-level reviews, inline comments, and issue comments could not be queried. |
Blast Radius Assessment
- Runs for all instances: No. The new methods run only when a child requests focus or requests a rectangle to be scrolled on screen.
- Startup impact: No.
- Static/shared state: No static or shared state introduced.
- Platform scope: Android-only active CarouselView handler in
Handlers/Items/Android.
CI Status
- Required-check result: undetermined
- Classification: tool unavailable
- Action taken: confidence capped at low. The caller supplied the gate result separately: Gate ✅ PASSED.
Findings
⚠️ Warning — RequestChildFocus StopScroll may miss asynchronous focus-scroll paths
src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:641-652
base.RequestChildFocus can schedule scrolling asynchronously. If ScrollState is still ScrollStateIdle immediately after the base call, the StopScroll() branch does not run. This likely does not invalidate the PR because RequestChildRectangleOnScreen returning false appears to suppress the primary cursor-rectangle path, but it makes the second override a best-effort safeguard rather than a complete independent interception point.
💡 Suggestion — Avoid inline platform directives in UI test methods
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue13323.cs:32-35 and src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue13323.cs:56-59
The repository UI-test guidance prefers platform-specific behavior behind extension helpers instead of inline #if ANDROID directives inside test methods. This is test readability guidance, not a correctness blocker.
Failure-Mode Probing
- What happens when a child control that is not an
EntrycallsRequestChildRectangleOnScreen? The PR suppresses it too. For a full-page pager this is defensible, but it is broader than the exact Entry cursor scenario. - What happens if the user is already dragging?
RequestChildFocusdoes not callStopScroll()when the carousel was not idle before focus, preserving user-driven swipes. - Does focus still propagate? Yes, the PR calls
base.RequestChildFocus, so Entry focus/keyboard behavior should continue while only the scroll side effect is suppressed. - Does loop mode need a separate handler implementation? No. Android has only the
Items/Androidimplementation; Items2 is iOS/MacCatalyst-only.
Verdict: NEEDS_DISCUSSION
Confidence: low
Summary: The Android fix is technically plausible and localized, and the supplied gate result indicates the regression tests validate the PR fix. Confidence remains low because GitHub context and CI checks are unavailable here, and because the RequestChildFocus safeguard may not catch asynchronous focus-scroll paths independently of the rectangle-scroll override.
🛠️ Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix | Minimal rectangle suppression: only override RequestChildRectangleOnScreen to return false; remove RequestChildFocus. |
2 files | Timed out during Android HostApp build/deploy before tests executed. Simpler but may miss RecyclerView internal focus path. | |
| 2 | try-fix | Focus-only deferred cancel: override RequestChildFocus and Post(StopScroll) after idle focus requests; no rectangle suppression. |
2 files | Timed out during Android HostApp build/deploy before tests executed. Handles async focus scrolling but may miss direct rectangle requests and may over-cancel focus requests. | |
| 3 | try-fix | Text-input-only rectangle suppression: suppress rectangle requests only when an EditText is involved; remove RequestChildFocus. |
2 files | Timed out during Android HostApp build/deploy before tests executed. Narrower blast radius but likely misses container/internal focus paths. | |
| PR | PR #34532 | Unconditionally suppress child rectangle scrolling and cancel focus-started scrolls when focus moves from idle to non-idle. | ✅ PASSED (Gate) | 4 files | Original PR. Gate result supplied by caller: tests fail without fix and pass with PR fix. |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| maui-expert-reviewer | 1 | Yes | Suggested the meaningful strategy space: minimal rectangle suppression, focus-only/deferred cancellation, conditional text-input suppression, plus a LayoutManager-level variant. |
| maui-expert-reviewer | 2 | No | After reviewing attempts and environment-blocked results, concluded remaining ideas are equivalent or riskier variants of the PR fix/candidates. |
Exhausted: Yes
Selected Fix: PR #34532 — It is the only fix with a supplied passing gate result. None of the alternative candidates reached test execution in this environment, and expert review found no remaining non-trivial approach likely to be better than the PR's combined rectangle + focus-path coverage.
🏁 Report — Final Recommendation
Comparative Report — PR #34532
Candidates Compared
| Rank | Candidate | Result | Assessment |
|---|---|---|---|
| 1 | pr |
✅ Passed supplied gate | Best candidate. It combines both relevant RecyclerView interception points: child rectangle scroll suppression and focus-scroll cancellation while preserving focus propagation. The Android regression tests fail without the PR and pass with it. |
| 2 | pr-plus-reviewer |
✅ Equivalent to pr |
Expert review found no actionable changes to apply, so this candidate is functionally identical to pr. It ranks below pr only because it adds no improvement over the raw PR fix. |
| 3 | try-fix-1 |
Simpler rectangle-only suppression, but it drops the focus-scroll safeguard and never reached test execution. It is less robust than the passing PR candidate. | |
| 4 | try-fix-3 |
Narrower text-input-only rectangle suppression, but it can miss container/internal request paths and drops the focus-scroll safeguard. It never reached test execution. | |
| 5 | try-fix-2 |
Focus-only deferred cancellation may catch async focus scrolls, but it does not block direct cursor rectangle requests and posts StopScroll after every idle focus request. It never reached test execution. |
Decision
Winner: pr
The raw PR fix is the only non-equivalent candidate with a supplied passing regression gate. It addresses both root-cause paths described by the PR: EditText/cursor rectangle requests and RecyclerView focus-driven scroll side effects. All try-fix candidates were blocked before test execution, so they cannot outrank a candidate with demonstrated fail-without/pass-with evidence.
Risk Notes
- The PR's behavior change is Android-only and localized to
MauiCarouselRecyclerView. - Suppressing child rectangle requests is broad, but appropriate for a full-page pager where child controls should not move the carousel page.
RequestChildFocuscallsbasefirst, preserving normal focus, keyboard, and accessibility propagation before cancelling unintended carousel scroll side effects.
🧭 Next Steps — review latest findings
No alternative fix was selected for this run. Review the session findings and CI results before merging.
…gned Entry (#34532) <!-- 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! ### Root Cause On Android, when an `Entry` inside a `CarouselView` receives focus, two independent `RecyclerView` mechanisms trigger unintended horizontal scrolls. First, `requestRectangleOnScreen()` is called to ensure the cursor is visible. For `Center` or `End` alignment, the cursor’s X position is greater than zero, so `RecyclerView` initiates a horizontal smooth scroll. With `Loop=True`, the large virtual item pool amplifies the scroll delta, often jumping to position 0. Second, `LinearLayoutManager.onRequestChildFocus()` also triggers a settling scroll on focus. This behavior is correct for lists but incorrect for a full-page pager like `CarouselView`, where items are never partially visible. `Start` alignment is unaffected because the cursor’s X position is zero, so no scroll is triggered. ### Description of Change In `MauiCarouselRecyclerView.cs`, two overrides were added. `RequestChildRectangleOnScreen` now returns `false` to suppress cursor-driven scroll requests. `RequestChildFocus` calls `base` to preserve normal focus, keyboard, and accessibility behavior, then calls `StopScroll()` to cancel the unintended scroll side-effect. Since `MauiCarouselRecyclerView` is used only by `CarouselView`, no conditional logic is required. The fix preserves expected focus behavior while preventing incorrect page jumps. ### Issues Fixed Fixes #13323 Tested the behaviour in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Screenshots | Before Issue Fix | After Issue Fix | |------------------|-----------------| | <video width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/0c35c184-c162-444e-98c2-afef1c48516b" /> | <video width="350" alt="withfix" src="https://github.com/user-attachments/assets/4e86e451-e0cc-4dad-be64-b3211b7d2326" /> | --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…gned Entry (#34532) <!-- 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! ### Root Cause On Android, when an `Entry` inside a `CarouselView` receives focus, two independent `RecyclerView` mechanisms trigger unintended horizontal scrolls. First, `requestRectangleOnScreen()` is called to ensure the cursor is visible. For `Center` or `End` alignment, the cursor’s X position is greater than zero, so `RecyclerView` initiates a horizontal smooth scroll. With `Loop=True`, the large virtual item pool amplifies the scroll delta, often jumping to position 0. Second, `LinearLayoutManager.onRequestChildFocus()` also triggers a settling scroll on focus. This behavior is correct for lists but incorrect for a full-page pager like `CarouselView`, where items are never partially visible. `Start` alignment is unaffected because the cursor’s X position is zero, so no scroll is triggered. ### Description of Change In `MauiCarouselRecyclerView.cs`, two overrides were added. `RequestChildRectangleOnScreen` now returns `false` to suppress cursor-driven scroll requests. `RequestChildFocus` calls `base` to preserve normal focus, keyboard, and accessibility behavior, then calls `StopScroll()` to cancel the unintended scroll side-effect. Since `MauiCarouselRecyclerView` is used only by `CarouselView`, no conditional logic is required. The fix preserves expected focus behavior while preventing incorrect page jumps. ### Issues Fixed Fixes #13323 Tested the behaviour in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Screenshots | Before Issue Fix | After Issue Fix | |------------------|-----------------| | <video width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/0c35c184-c162-444e-98c2-afef1c48516b" /> | <video width="350" alt="withfix" src="https://github.com/user-attachments/assets/4e86e451-e0cc-4dad-be64-b3211b7d2326" /> | --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…gned Entry (#34532) <!-- 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! ### Root Cause On Android, when an `Entry` inside a `CarouselView` receives focus, two independent `RecyclerView` mechanisms trigger unintended horizontal scrolls. First, `requestRectangleOnScreen()` is called to ensure the cursor is visible. For `Center` or `End` alignment, the cursor’s X position is greater than zero, so `RecyclerView` initiates a horizontal smooth scroll. With `Loop=True`, the large virtual item pool amplifies the scroll delta, often jumping to position 0. Second, `LinearLayoutManager.onRequestChildFocus()` also triggers a settling scroll on focus. This behavior is correct for lists but incorrect for a full-page pager like `CarouselView`, where items are never partially visible. `Start` alignment is unaffected because the cursor’s X position is zero, so no scroll is triggered. ### Description of Change In `MauiCarouselRecyclerView.cs`, two overrides were added. `RequestChildRectangleOnScreen` now returns `false` to suppress cursor-driven scroll requests. `RequestChildFocus` calls `base` to preserve normal focus, keyboard, and accessibility behavior, then calls `StopScroll()` to cancel the unintended scroll side-effect. Since `MauiCarouselRecyclerView` is used only by `CarouselView`, no conditional logic is required. The fix preserves expected focus behavior while preventing incorrect page jumps. ### Issues Fixed Fixes #13323 Tested the behaviour in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Screenshots | Before Issue Fix | After Issue Fix | |------------------|-----------------| | <video width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/0c35c184-c162-444e-98c2-afef1c48516b" /> | <video width="350" alt="withfix" src="https://github.com/user-attachments/assets/4e86e451-e0cc-4dad-be64-b3211b7d2326" /> | --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…gned Entry (#34532) <!-- 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! ### Root Cause On Android, when an `Entry` inside a `CarouselView` receives focus, two independent `RecyclerView` mechanisms trigger unintended horizontal scrolls. First, `requestRectangleOnScreen()` is called to ensure the cursor is visible. For `Center` or `End` alignment, the cursor’s X position is greater than zero, so `RecyclerView` initiates a horizontal smooth scroll. With `Loop=True`, the large virtual item pool amplifies the scroll delta, often jumping to position 0. Second, `LinearLayoutManager.onRequestChildFocus()` also triggers a settling scroll on focus. This behavior is correct for lists but incorrect for a full-page pager like `CarouselView`, where items are never partially visible. `Start` alignment is unaffected because the cursor’s X position is zero, so no scroll is triggered. ### Description of Change In `MauiCarouselRecyclerView.cs`, two overrides were added. `RequestChildRectangleOnScreen` now returns `false` to suppress cursor-driven scroll requests. `RequestChildFocus` calls `base` to preserve normal focus, keyboard, and accessibility behavior, then calls `StopScroll()` to cancel the unintended scroll side-effect. Since `MauiCarouselRecyclerView` is used only by `CarouselView`, no conditional logic is required. The fix preserves expected focus behavior while preventing incorrect page jumps. ### Issues Fixed Fixes #13323 Tested the behaviour in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Screenshots | Before Issue Fix | After Issue Fix | |------------------|-----------------| | <video width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/0c35c184-c162-444e-98c2-afef1c48516b" /> | <video width="350" alt="withfix" src="https://github.com/user-attachments/assets/4e86e451-e0cc-4dad-be64-b3211b7d2326" /> | --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…gned Entry (#34532) <!-- 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! ### Root Cause On Android, when an `Entry` inside a `CarouselView` receives focus, two independent `RecyclerView` mechanisms trigger unintended horizontal scrolls. First, `requestRectangleOnScreen()` is called to ensure the cursor is visible. For `Center` or `End` alignment, the cursor’s X position is greater than zero, so `RecyclerView` initiates a horizontal smooth scroll. With `Loop=True`, the large virtual item pool amplifies the scroll delta, often jumping to position 0. Second, `LinearLayoutManager.onRequestChildFocus()` also triggers a settling scroll on focus. This behavior is correct for lists but incorrect for a full-page pager like `CarouselView`, where items are never partially visible. `Start` alignment is unaffected because the cursor’s X position is zero, so no scroll is triggered. ### Description of Change In `MauiCarouselRecyclerView.cs`, two overrides were added. `RequestChildRectangleOnScreen` now returns `false` to suppress cursor-driven scroll requests. `RequestChildFocus` calls `base` to preserve normal focus, keyboard, and accessibility behavior, then calls `StopScroll()` to cancel the unintended scroll side-effect. Since `MauiCarouselRecyclerView` is used only by `CarouselView`, no conditional logic is required. The fix preserves expected focus behavior while preventing incorrect page jumps. ### Issues Fixed Fixes #13323 Tested the behaviour in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Screenshots | Before Issue Fix | After Issue Fix | |------------------|-----------------| | <video width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/0c35c184-c162-444e-98c2-afef1c48516b" /> | <video width="350" alt="withfix" src="https://github.com/user-attachments/assets/4e86e451-e0cc-4dad-be64-b3211b7d2326" /> | --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…gned Entry (#34532) <!-- 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! ### Root Cause On Android, when an `Entry` inside a `CarouselView` receives focus, two independent `RecyclerView` mechanisms trigger unintended horizontal scrolls. First, `requestRectangleOnScreen()` is called to ensure the cursor is visible. For `Center` or `End` alignment, the cursor’s X position is greater than zero, so `RecyclerView` initiates a horizontal smooth scroll. With `Loop=True`, the large virtual item pool amplifies the scroll delta, often jumping to position 0. Second, `LinearLayoutManager.onRequestChildFocus()` also triggers a settling scroll on focus. This behavior is correct for lists but incorrect for a full-page pager like `CarouselView`, where items are never partially visible. `Start` alignment is unaffected because the cursor’s X position is zero, so no scroll is triggered. ### Description of Change In `MauiCarouselRecyclerView.cs`, two overrides were added. `RequestChildRectangleOnScreen` now returns `false` to suppress cursor-driven scroll requests. `RequestChildFocus` calls `base` to preserve normal focus, keyboard, and accessibility behavior, then calls `StopScroll()` to cancel the unintended scroll side-effect. Since `MauiCarouselRecyclerView` is used only by `CarouselView`, no conditional logic is required. The fix preserves expected focus behavior while preventing incorrect page jumps. ### Issues Fixed Fixes #13323 Tested the behaviour in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Screenshots | Before Issue Fix | After Issue Fix | |------------------|-----------------| | <video width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/0c35c184-c162-444e-98c2-afef1c48516b" /> | <video width="350" alt="withfix" src="https://github.com/user-attachments/assets/4e86e451-e0cc-4dad-be64-b3211b7d2326" /> | --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…gned Entry (#34532) <!-- 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! ### Root Cause On Android, when an `Entry` inside a `CarouselView` receives focus, two independent `RecyclerView` mechanisms trigger unintended horizontal scrolls. First, `requestRectangleOnScreen()` is called to ensure the cursor is visible. For `Center` or `End` alignment, the cursor’s X position is greater than zero, so `RecyclerView` initiates a horizontal smooth scroll. With `Loop=True`, the large virtual item pool amplifies the scroll delta, often jumping to position 0. Second, `LinearLayoutManager.onRequestChildFocus()` also triggers a settling scroll on focus. This behavior is correct for lists but incorrect for a full-page pager like `CarouselView`, where items are never partially visible. `Start` alignment is unaffected because the cursor’s X position is zero, so no scroll is triggered. ### Description of Change In `MauiCarouselRecyclerView.cs`, two overrides were added. `RequestChildRectangleOnScreen` now returns `false` to suppress cursor-driven scroll requests. `RequestChildFocus` calls `base` to preserve normal focus, keyboard, and accessibility behavior, then calls `StopScroll()` to cancel the unintended scroll side-effect. Since `MauiCarouselRecyclerView` is used only by `CarouselView`, no conditional logic is required. The fix preserves expected focus behavior while preventing incorrect page jumps. ### Issues Fixed Fixes #13323 Tested the behaviour in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Screenshots | Before Issue Fix | After Issue Fix | |------------------|-----------------| | <video width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/0c35c184-c162-444e-98c2-afef1c48516b" /> | <video width="350" alt="withfix" src="https://github.com/user-attachments/assets/4e86e451-e0cc-4dad-be64-b3211b7d2326" /> | --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…gned Entry (#34532) <!-- 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! ### Root Cause On Android, when an `Entry` inside a `CarouselView` receives focus, two independent `RecyclerView` mechanisms trigger unintended horizontal scrolls. First, `requestRectangleOnScreen()` is called to ensure the cursor is visible. For `Center` or `End` alignment, the cursor’s X position is greater than zero, so `RecyclerView` initiates a horizontal smooth scroll. With `Loop=True`, the large virtual item pool amplifies the scroll delta, often jumping to position 0. Second, `LinearLayoutManager.onRequestChildFocus()` also triggers a settling scroll on focus. This behavior is correct for lists but incorrect for a full-page pager like `CarouselView`, where items are never partially visible. `Start` alignment is unaffected because the cursor’s X position is zero, so no scroll is triggered. ### Description of Change In `MauiCarouselRecyclerView.cs`, two overrides were added. `RequestChildRectangleOnScreen` now returns `false` to suppress cursor-driven scroll requests. `RequestChildFocus` calls `base` to preserve normal focus, keyboard, and accessibility behavior, then calls `StopScroll()` to cancel the unintended scroll side-effect. Since `MauiCarouselRecyclerView` is used only by `CarouselView`, no conditional logic is required. The fix preserves expected focus behavior while preventing incorrect page jumps. ### Issues Fixed Fixes #13323 Tested the behaviour in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Screenshots | Before Issue Fix | After Issue Fix | |------------------|-----------------| | <video width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/0c35c184-c162-444e-98c2-afef1c48516b" /> | <video width="350" alt="withfix" src="https://github.com/user-attachments/assets/4e86e451-e0cc-4dad-be64-b3211b7d2326" /> | --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
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, when an
Entryinside aCarouselViewreceives focus, two independentRecyclerViewmechanisms trigger unintended horizontal scrolls.First,
requestRectangleOnScreen()is called to ensure the cursor is visible. ForCenterorEndalignment, the cursor’s X position is greater than zero, soRecyclerViewinitiates a horizontal smooth scroll. WithLoop=True, the large virtual item pool amplifies the scroll delta, often jumping to position 0.Second,
LinearLayoutManager.onRequestChildFocus()also triggers a settling scroll on focus. This behavior is correct for lists but incorrect for a full-page pager likeCarouselView, where items are never partially visible.Startalignment is unaffected because the cursor’s X position is zero, so no scroll is triggered.Description of Change
In
MauiCarouselRecyclerView.cs, two overrides were added.RequestChildRectangleOnScreennow returnsfalseto suppress cursor-driven scroll requests.RequestChildFocuscallsbaseto preserve normal focus, keyboard, and accessibility behavior, then callsStopScroll()to cancel the unintended scroll side-effect.Since
MauiCarouselRecyclerViewis used only byCarouselView, no conditional logic is required. The fix preserves expected focus behavior while preventing incorrect page jumps.Issues Fixed
Fixes #13323
Tested the behaviour in the following platforms
Screenshots
BeforeFix.25.mov
AfterFix.31.mov