[Android] Implement material3 support for CheckBox#33339
[Android] Implement material3 support for CheckBox#33339PureWeen merged 6 commits intodotnet:inflight/currentfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR implements Material 3 support for CheckBox on Android by introducing theme-aware checkbox tinting. The implementation caches the default Material 3 button tint and uses it when no custom foreground is specified, while preserving the accent color behavior for Material 2.
Key Changes:
- Added static caching of default Material 3 button tint list to avoid recomputation
- Updated color state list logic to differentiate between Material 2 and Material 3 themes
- Reorganized return statements to handle Material 3 and Material 2 code paths separately
|
|
||
| if (RuntimeFeature.IsMaterial3Enabled) | ||
| { | ||
| // Save the default button tint list |
There was a problem hiding this comment.
The comment "Save the default button tint list" is misleading because this code doesn't just save the value - it uses null-coalescing to save it only if it hasn't been saved before. The comment would be more accurate as "Cache the default button tint list if not already cached" or "Initialize the default button tint list cache".
| // Save the default button tint list | |
| // Cache the default button tint list if not already cached |
| _defaultButtonTintList ??= platformCheckBox.ButtonTintList; | ||
|
|
||
| // Material 3: Use the default theme's buttonTint | ||
| if (_defaultButtonTintList is not null) | ||
| { | ||
| return _defaultButtonTintList; | ||
| } |
There was a problem hiding this comment.
The logic on line 52 caches platformCheckBox.ButtonTintList from the first CheckBox instance created. However, if the first CheckBox's ButtonTintList is null (which can happen in certain scenarios), the cache will be set to null and then the check on line 55 will fail, causing fallthrough to the Material 2 logic even when Material 3 is enabled.
This creates an inconsistent state where Material 3 is enabled but Material 2 accent colors are used. Consider checking if ButtonTintList is null before caching it, or handle the null case differently.
| { | ||
| public static class CheckBoxExtensions | ||
| { | ||
| static ColorStateList? _defaultButtonTintList; |
There was a problem hiding this comment.
The static field _defaultButtonTintList creates a global cache that is shared across all CheckBox instances in the application. This approach has several problems:
-
Per-Activity theming: Different Activities in the same application can use different themes. By caching the first CheckBox's ButtonTintList globally, all subsequent CheckBoxes will use this cached value regardless of their Activity's theme.
-
Theme switching: If the app's theme changes at runtime (e.g., dark mode toggle, Material 2/3 toggle), this cached value won't be updated, causing CheckBoxes to retain the old theme's colors.
-
Thread safety: The null-coalescing assignment operator
??=on line 52 is not thread-safe, which could lead to race conditions if multiple CheckBoxes are created simultaneously on different threads.
Consider either:
- Removing the cache and always reading
platformCheckBox.ButtonTintListwhen Material 3 is enabled and no foreground is set - Implementing a per-Context or per-Activity cache if performance is critical
- Using a thread-safe caching mechanism if needed
| } | ||
| else | ||
| { | ||
|
|
There was a problem hiding this comment.
There's an unnecessary empty line here. This should be removed to maintain code consistency.
|
/azp run maui-pr-uitests |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Address review feedback on PR dotnet#33339: 1. Replace static ColorStateList cache with per-instance ConditionalWeakTable - Fixes per-Activity theming (different Activities can have different themes) - Fixes theme switching at runtime (dark mode, Material2/3 toggle) - Provides thread safety (no shared mutable state) 2. Improve code structure - Remove unnecessary else block for cleaner flow - Add descriptive comments explaining the caching strategy The original static cache would capture the first checkbox's theme tint and reuse it for all subsequent checkboxes, causing incorrect colors when themes differ across Activities or change at runtime.
|
I've pushed a commit that addresses the review feedback about static caching: Changes Made
Why This MattersThe original static cache would capture the first checkbox's theme tint and reuse it for all subsequent checkboxes, causing incorrect colors when:
Validation
|
StephaneDelcroix
left a comment
There was a problem hiding this comment.
LGTM!
The Material3 checkbox support looks good. The per-instance caching approach using ConditionalWeakTable properly handles:
- Per-Activity theming
- Runtime theme switching
- Thread safety
The fix correctly preserves the original theme's ButtonTintList for each checkbox instance before modification, ensuring Material3 checkboxes use the proper theme colors.
Tested:
- ✅ All CheckBox unit tests pass
- ✅ Full Controls.Core.UnitTests suite passes (5,428 tests)
<!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of Change This pull request updates the way checkbox tint colors are handled on Android, improving compatibility with both Material 2 and Material 3 themes. The main focus is on ensuring that the correct default or accent color is used for checkbox foregrounds depending on the Material version in use. **Theme-aware checkbox tinting:** * Introduced a static field `_defaultButtonTintList` in `CheckBoxExtensions` to cache the default button tint for Material 3 themes, ensuring consistent appearance and avoiding unnecessary recomputation. * Updated the `GetColorStateList` method to: - Use the default theme's button tint when Material 3 is enabled, falling back to the cached `_defaultButtonTintList` if available. - Continue using the accent color for Material 2 themes, preserving existing behavior. ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #33338 ### Screenshots Material Design Spec - [CheckBox](https://m3.material.io/components/checkbox/specs) | Material 2 | Material 3 | |----------|----------| | <img src="https://github.com/user-attachments/assets/8bce9689-a698-49af-862f-24e56ec4f3cb"> | <img src="https://github.com/user-attachments/assets/978b27eb-0e67-451c-8a3b-927434d6389a"> | --------- Co-authored-by: Stephane Delcroix <stephane@delcroix.org>
<!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of Change This pull request updates the way checkbox tint colors are handled on Android, improving compatibility with both Material 2 and Material 3 themes. The main focus is on ensuring that the correct default or accent color is used for checkbox foregrounds depending on the Material version in use. **Theme-aware checkbox tinting:** * Introduced a static field `_defaultButtonTintList` in `CheckBoxExtensions` to cache the default button tint for Material 3 themes, ensuring consistent appearance and avoiding unnecessary recomputation. * Updated the `GetColorStateList` method to: - Use the default theme's button tint when Material 3 is enabled, falling back to the cached `_defaultButtonTintList` if available. - Continue using the accent color for Material 2 themes, preserving existing behavior. ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #33338 ### Screenshots Material Design Spec - [CheckBox](https://m3.material.io/components/checkbox/specs) | Material 2 | Material 3 | |----------|----------| | <img src="https://github.com/user-attachments/assets/8bce9689-a698-49af-862f-24e56ec4f3cb"> | <img src="https://github.com/user-attachments/assets/978b27eb-0e67-451c-8a3b-927434d6389a"> | --------- Co-authored-by: Stephane Delcroix <stephane@delcroix.org>
<!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of Change This pull request updates the way checkbox tint colors are handled on Android, improving compatibility with both Material 2 and Material 3 themes. The main focus is on ensuring that the correct default or accent color is used for checkbox foregrounds depending on the Material version in use. **Theme-aware checkbox tinting:** * Introduced a static field `_defaultButtonTintList` in `CheckBoxExtensions` to cache the default button tint for Material 3 themes, ensuring consistent appearance and avoiding unnecessary recomputation. * Updated the `GetColorStateList` method to: - Use the default theme's button tint when Material 3 is enabled, falling back to the cached `_defaultButtonTintList` if available. - Continue using the accent color for Material 2 themes, preserving existing behavior. ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #33338 ### Screenshots Material Design Spec - [CheckBox](https://m3.material.io/components/checkbox/specs) | Material 2 | Material 3 | |----------|----------| | <img src="https://github.com/user-attachments/assets/8bce9689-a698-49af-862f-24e56ec4f3cb"> | <img src="https://github.com/user-attachments/assets/978b27eb-0e67-451c-8a3b-927434d6389a"> | --------- Co-authored-by: Stephane Delcroix <stephane@delcroix.org>
<!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of Change This pull request updates the way checkbox tint colors are handled on Android, improving compatibility with both Material 2 and Material 3 themes. The main focus is on ensuring that the correct default or accent color is used for checkbox foregrounds depending on the Material version in use. **Theme-aware checkbox tinting:** * Introduced a static field `_defaultButtonTintList` in `CheckBoxExtensions` to cache the default button tint for Material 3 themes, ensuring consistent appearance and avoiding unnecessary recomputation. * Updated the `GetColorStateList` method to: - Use the default theme's button tint when Material 3 is enabled, falling back to the cached `_defaultButtonTintList` if available. - Continue using the accent color for Material 2 themes, preserving existing behavior. ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #33338 ### Screenshots Material Design Spec - [CheckBox](https://m3.material.io/components/checkbox/specs) | Material 2 | Material 3 | |----------|----------| | <img src="https://github.com/user-attachments/assets/8bce9689-a698-49af-862f-24e56ec4f3cb"> | <img src="https://github.com/user-attachments/assets/978b27eb-0e67-451c-8a3b-927434d6389a"> | --------- Co-authored-by: Stephane Delcroix <stephane@delcroix.org>
<!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of Change This pull request updates the way checkbox tint colors are handled on Android, improving compatibility with both Material 2 and Material 3 themes. The main focus is on ensuring that the correct default or accent color is used for checkbox foregrounds depending on the Material version in use. **Theme-aware checkbox tinting:** * Introduced a static field `_defaultButtonTintList` in `CheckBoxExtensions` to cache the default button tint for Material 3 themes, ensuring consistent appearance and avoiding unnecessary recomputation. * Updated the `GetColorStateList` method to: - Use the default theme's button tint when Material 3 is enabled, falling back to the cached `_defaultButtonTintList` if available. - Continue using the accent color for Material 2 themes, preserving existing behavior. ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #33338 ### Screenshots Material Design Spec - [CheckBox](https://m3.material.io/components/checkbox/specs) | Material 2 | Material 3 | |----------|----------| | <img src="https://github.com/user-attachments/assets/8bce9689-a698-49af-862f-24e56ec4f3cb"> | <img src="https://github.com/user-attachments/assets/978b27eb-0e67-451c-8a3b-927434d6389a"> | --------- Co-authored-by: Stephane Delcroix <stephane@delcroix.org>
<!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of Change This pull request updates the way checkbox tint colors are handled on Android, improving compatibility with both Material 2 and Material 3 themes. The main focus is on ensuring that the correct default or accent color is used for checkbox foregrounds depending on the Material version in use. **Theme-aware checkbox tinting:** * Introduced a static field `_defaultButtonTintList` in `CheckBoxExtensions` to cache the default button tint for Material 3 themes, ensuring consistent appearance and avoiding unnecessary recomputation. * Updated the `GetColorStateList` method to: - Use the default theme's button tint when Material 3 is enabled, falling back to the cached `_defaultButtonTintList` if available. - Continue using the accent color for Material 2 themes, preserving existing behavior. ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #33338 ### Screenshots Material Design Spec - [CheckBox](https://m3.material.io/components/checkbox/specs) | Material 2 | Material 3 | |----------|----------| | <img src="https://github.com/user-attachments/assets/8bce9689-a698-49af-862f-24e56ec4f3cb"> | <img src="https://github.com/user-attachments/assets/978b27eb-0e67-451c-8a3b-927434d6389a"> | --------- Co-authored-by: Stephane Delcroix <stephane@delcroix.org>
<!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of Change This pull request updates the way checkbox tint colors are handled on Android, improving compatibility with both Material 2 and Material 3 themes. The main focus is on ensuring that the correct default or accent color is used for checkbox foregrounds depending on the Material version in use. **Theme-aware checkbox tinting:** * Introduced a static field `_defaultButtonTintList` in `CheckBoxExtensions` to cache the default button tint for Material 3 themes, ensuring consistent appearance and avoiding unnecessary recomputation. * Updated the `GetColorStateList` method to: - Use the default theme's button tint when Material 3 is enabled, falling back to the cached `_defaultButtonTintList` if available. - Continue using the accent color for Material 2 themes, preserving existing behavior. ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #33338 ### Screenshots Material Design Spec - [CheckBox](https://m3.material.io/components/checkbox/specs) | Material 2 | Material 3 | |----------|----------| | <img src="https://github.com/user-attachments/assets/8bce9689-a698-49af-862f-24e56ec4f3cb"> | <img src="https://github.com/user-attachments/assets/978b27eb-0e67-451c-8a3b-927434d6389a"> | --------- Co-authored-by: Stephane Delcroix <stephane@delcroix.org>
## What's Coming .NET MAUI inflight/candidate introduces significant improvements across all platforms with focus on quality, performance, and developer experience. This release includes 16 commits with various improvements, bug fixes, and enhancements. ## Checkbox - [Android] Implement material3 support for CheckBox by @HarishwaranVijayakumar in #33339 <details> <summary>🔧 Fixes</summary> - [Implement Material3 Support for CheckBox](#33338) </details> ## CollectionView - [Android] Fixed EmptyView doesn’t display when CollectionView is placed inside a VerticalStackLayout by @NanthiniMahalingam in #33134 <details> <summary>🔧 Fixes</summary> - [CollectionView does not show an EmptyView template with an empty collection](#32932) </details> ## Essentials - [Windows]Fix NullReferenceException in OpenReadAsync for FileResult created with full path by @devanathan-vaithiyanathan in #28238 <details> <summary>🔧 Fixes</summary> - [[Windows] FileResult(string fullPath) not initialized properly](#26858) </details> ## Image - Fix Glide IllegalArgumentException in MauiCustomTarget.clear() for destroyed activities by @jfversluis via @Copilot in #29780 <details> <summary>🔧 Fixes</summary> - [java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity - glide](#29699) </details> ## Label - [Android] Fix for Label WordWrap width issue causing HorizontalOptions misalignment by @praveenkumarkarunanithi in #33281 <details> <summary>🔧 Fixes</summary> - [[Android] Unexpected Line Breaks in Android, Label with WordWrap Mode Due to Trailing Space.](#31782) - [Label not sized correctly on Android](#27614) </details> - Fix to Improve Flyout Accessibility by Adjusting UITableViewController Labels by @SuthiYuvaraj in #31619 <details> <summary>🔧 Fixes</summary> - [Navigation section present under hamburger are programmatically define as table :A11y_.NET maui_User can get all the insights of Dashboard_Devtools](#30894) </details> ## Mediapicker - [Regression][iOS] Fix MediaPicker PickPhotosAsync getting file name in contentType property by @devanathan-vaithiyanathan in #33390 <details> <summary>🔧 Fixes</summary> - [[iOS] MediaPicker PickPhotosAsync getting file name in contentType property](#33348) </details> ## Navigation - Fix handler not disconnected when removing non visible pages using RemovePage() by @Vignesh-SF3580 in #32289 <details> <summary>🔧 Fixes</summary> - [NavigationPage.Navigation.RemovePage() fails to disconnect handlers when removing pages, unlike ContentPage.Navigation.RemovePage()](#32239) </details> ## Picker - [Android] Fix Picker IsOpen not reset when picker is dismissed by @devanathan-vaithiyanathan in #33332 <details> <summary>🔧 Fixes</summary> - [[Android] Picker IsOpen not reset when picker is dismissed](#33331) </details> ## Shell - [iOS & Catalyst ] Fixed IsEnabled property should work on Tabs by @SubhikshaSf4851 in #33369 <details> <summary>🔧 Fixes</summary> - [[Catalyst] TabBarBackgroundColor, TabBarUnselectedColor, and IsEnabled Not Working as Expected in Shell](#33158) </details> - [iOS,Windows] Fix navigation bar colors not resetting when switching ShellContent by @Vignesh-SF3580 in #33228 <details> <summary>🔧 Fixes</summary> - [[iOS, Windows] Shell Navigation bar colors are not updated correctly when switching ShellContent](#33227) </details> - [iOS] Fixed Shell navigation on search handler suggestion selection by @SubhikshaSf4851 in #33406 <details> <summary>🔧 Fixes</summary> - [[iOS] Clicking on search suggestions fails to navigate to detail page correctly](#33356) </details> ## Templates - Fix VoiceOver doesnot announces the State of the ComboBox by @SuthiYuvaraj in #32286 ## Xaml - [XSG][BindingSourceGen] Add support for CommunityToolkit.Mvvm ObservablePropertyAttribute by @simonrozsival via @Copilot in #33028 <details> <summary>🔧 Fixes</summary> - [[XSG] Add heuristic to support bindable properties generated by other source generators](#32597) </details> <details> <summary>📦 Other (2)</summary> - [XSG] Improve diagnostic reporting during binding compilation by @simonrozsival via @Copilot in #32905 - [Testing] Fixed Test case failure in PR 33574 - [01/19/2026] Candidate - 1 by @TamilarasanSF4853 in #33602 </details> **Full Changelog**: main...inflight/candidate
Description of Change
This pull request updates the way checkbox tint colors are handled on Android, improving compatibility with both Material 2 and Material 3 themes. The main focus is on ensuring that the correct default or accent color is used for checkbox foregrounds depending on the Material version in use.
Theme-aware checkbox tinting:
_defaultButtonTintListinCheckBoxExtensionsto cache the default button tint for Material 3 themes, ensuring consistent appearance and avoiding unnecessary recomputation.GetColorStateListmethod to:_defaultButtonTintListif available.Issues Fixed
Fixes #33338
Screenshots
Material Design Spec - CheckBox