Android MaterialButtonToggleGroup样式切换异常问题求助
Hey Scott, let's break down why your toggle group isn't switching styles correctly when selecting the Units button. The main problems come from how you're hardcoding button states in styles and using the wrong method to update styles. Here's the breakdown and fix:
What's Wrong With Your Current Setup
Hardcoded Checked State in Styles
You've setandroid:checked="true"andfalsedirectly in your Selected/NotSelected styles. This overrides theMaterialButtonToggleGroup's ability to manage the checked state of the buttons—once the style is applied, the button's state is locked, so toggling won't update the appearance.Using
setTextAppearanceIncorrectly
ThesetTextAppearance()method only updates text-related style properties (like font, text color in some cases), but it won't affectbackgroundTint,strokeColor, or other non-text attributes. That's why switching to Units doesn't update the background or stroke as expected.Ignoring Material Component State Selectors
Material Components are designed to use state-based selectors to handle style changes automatically, but you're trying to manually swap styles instead of leveraging this built-in functionality.
Step-by-Step Fix
1. Create State-Based Selectors
First, create drawable selectors to handle background and text color changes based on the button's checked state.
res/drawable/toggle_background_selector.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@color/dark_blue" android:state_checked="true"/> <item android:color="@color/white" android:state_checked="false"/> </selector>
res/drawable/toggle_text_color_selector.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@color/white" android:state_checked="true"/> <item android:color="@color/dark_blue" android:state_checked="false"/> </selector>
2. Update Your Button Style
Replace your two separate styles with a single base style that uses the selectors. This way, the button automatically switches styles based on its checked state:
<style name="Theme.MyApp.Toggle.Button" parent="Widget.MaterialComponents.Button.OutlinedButton"> <item name="strokeColor">@color/dark_blue</item> <item name="backgroundTint">@drawable/toggle_background_selector</item> <item name="android:textColor">@drawable/toggle_text_color_selector</item> </style>
3. Simplify Your Layout
Update your MaterialButtonToggleGroup to use the single style for both buttons, and let the toggle group manage the checked state (you already have singleSelection and selectionRequired set correctly):
<com.google.android.material.button.MaterialButtonToggleGroup android:id="@+id/scanningModeToggleGroup" <!-- Add an ID for easier access --> android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_margin="10dp" app:selectionRequired="true" app:singleSelection="true" app:checkedButton="@id/btnCases"> <com.google.android.material.button.MaterialButton android:id="@+id/btnCases" android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/Theme.MyApp.Toggle.Button" android:onClick="@{() -> viewModel.changeScanningMode(true)}" android:text="Cases" /> <com.google.android.material.button.MaterialButton android:id="@+id/btnUnits" android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/Theme.MyApp.Toggle.Button" android:onClick="@{() -> viewModel.changeScanningMode(false)}" android:text="Units" /> </com.google.android.material.button.MaterialButtonToggleGroup>
4. Update Your ViewModel Listener Logic
Instead of manually swapping styles, just tell the toggle group which button should be checked. The selectors will handle the style changes automatically:
val toggleGroup = binding.root.findViewById<MaterialButtonToggleGroup>(R.id.scanningModeToggleGroup) when (it) { ScanningModes.CASE -> { toggleGroup.check(R.id.btnCases) } ScanningModes.UNIT -> { toggleGroup.check(R.id.btnUnits) } }
Why This Works
- The state selectors automatically update the button's appearance whenever its
checkedstate changes, which is managed by theMaterialButtonToggleGroup. - You're no longer overriding the button's checked state with hardcoded style values, so the toggle group can properly control which button is selected.
- Using
toggleGroup.check()ensures that the group's single-selection rule is enforced, and all state changes are handled consistently.
内容的提问来源于stack exchange,提问作者Scott Salyer

