-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Fix for Preventing Incorrect TalkBack Announcements During CollectionView Deselection on Android #29818
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
/azp run MAUI-UITests-public |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
This PR should also fix #30833 |
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
| } | ||
|
|
||
| var position = GetPositionForItem(selectedItem); | ||
| HashSet<object> selectedSet; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The MarkPlatformSelection method creates a new HashSet<object> on every call, which could impact performance during frequent selection changes. Could create a single one, and reuse it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jsuarezruiz Thanks for the feedback. I’ve updated the fix to reuse a single _selectedSet by clearing and updating it instead of creating a new HashSet<object> each time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes incorrect TalkBack announcements during CollectionView deselection on Android by restructuring the selection update logic to avoid unnecessary clear-and-reselect cycles that confuse accessibility services.
Key changes:
- Replaced the "clear all and reselect" pattern with a single-pass update that only modifies items whose selection state actually changed
- Added missing native selection state synchronization to ensure visual state aligns with logical state
- Centralized selection logic to improve maintainability and prevent TalkBack from announcing incorrect items during deselection
Reviewed Changes
Copilot reviewed 6 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue21375.cs | Adds UI test for CollectionView selection behavior with accessibility considerations |
| src/Controls/tests/TestCases.HostApp/Issues/Issue21375.xaml.cs | Creates test page demonstrating CollectionView selection across different platforms |
| src/Controls/tests/TestCases.HostApp/Issues/Issue21375.xaml | Defines XAML layout for the CollectionView selection test page |
| src/Controls/src/Core/Platform/Android/Extensions/RecyclerViewExtensions.cs | Simplifies selection update logic to use centralized method call |
| src/Controls/src/Core/Handlers/Items/Android/SelectableViewHolder.cs | Adds missing native selection state synchronization |
| src/Controls/src/Core/Handlers/Items/Android/Adapters/SelectableItemsViewAdapter.cs | Refactors selection logic to avoid clear-and-reselect pattern that causes TalkBack issues |
| @@ -0,0 +1,51 @@ | |||
| #if !IOS && !MACCATALYST // Test excluded for iOS/macCatalyst as the accessibility implementation was reverted in PR-https://github.com/dotnet/maui/pull/29827 | |||
Copilot
AI
Sep 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test case has been properly created in TestCases.Shared.Tests and has a corresponding UI implementation in TestCases.HostApp. The test includes appropriate automation IDs and validates the expected behavior through screenshot verification, which aligns with the testing guidelines.
Copilot uses AI. Check for mistakes.
| } | ||
|
|
||
| internal void MarkPlatformSelection(object selectedItem) | ||
| internal void MarkPlatformSelection(SelectableItemsView selectableItemsView) |
Copilot
AI
Sep 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change modifies the method signature of MarkPlatformSelection from accepting a single item to accepting a SelectableItemsView. This is a potentially breaking change to the internal API that should be reviewed carefully, as it affects how selection state is managed across the platform.
Copilot uses AI. Check for mistakes.
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
|
/rebase |
# Conflicts: # src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue21375.cs
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
Root Cause
The issue arises from how Android's
CollectionViewmanages selection state changes in combination with TalkBack accessibility announcements. The original implementation followed a "clear all and reselect" strategy: it first cleared all selections usingadapter.ClearPlatformSelection(), then reselected each item by callingadapter.MarkPlatformSelection(item).When TalkBack is active, it detects these selection state changes. However, it typically does not announce deselections (i.e., when
IsSelectedchanges fromtruetofalse), but it does announce selections (falsetotrue). As a result, when a user deselects an item, TalkBack incorrectly announces one of the reselected items (often the first one), leading to a misleading and confusing accessibility experience.Description of Change
To resolve the issue, the selection update logic in
CollectionViewwas restructured to avoid the "clear and reselect" pattern. TheMarkPlatformSelectionmethod inSelectableItemsViewAdapter.cswas updated to accept the fullSelectableItemsViewrather than a single item. Within this method, selection states are now processed in a single pass using aHashSetfor efficient lookup, updating only the items whose selection states have actually changed. This eliminates unnecessary deselect/reselect cycles and prevents incorrect TalkBack announcements. Additionally, the missing lineItemView.Selected = _isSelectedwas added toSelectableViewHolder.csto ensure that the native selection visual state aligns with the logical selection state. Finally,RecyclerViewExtensions.UpdateSelectionwas simplified to make a single call toMarkPlatformSelection, centralizing the selection logic and improving maintainability.Issues Fixed
Fixes #29455
Tested the behaviour in the following platforms
Note
iOS/macCatalyst test exclusion needs to be removed once accessibility implementation is restored (originally reverted in #29827)
Output Screenshot
withoutfix.mov
withfix.mov