Reputation: 2475
I am in the process of building my first Android app and am running into an issue that should seemingly be very simple, but I'm at a loss on why it won't work. I am trying to use a MaterialButtonGroup
where a selection is both required and only one option can be selected at a time. The XML for this is:
<com.google.android.material.button.MaterialButtonToggleGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
app:selectionRequired="true"
android:layout_margin="10dp"
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.Selected"
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.NotSelected"
android:onClick="@{() -> viewModel.changeScanningMode(false)}"
android:text="Units" />
</com.google.android.material.button.MaterialButtonToggleGroup>
The two buttons inside represent the either/or option (scanning cases or units with a handheld scanner). There are two styles I've created - Selected
and NotSelected
- which have a parent style of OutlinedButton
from MaterialComponents
and look like this:
<style name="Theme.MyApp.Toggle.Selected" parent="Widget.MaterialComponents.Button.OutlinedButton">
<item name="android:checked">true</item>
<item name="backgroundTint">@color/dark_blue</item>
<item name="android:textColor">@color/white</item>
<item name="strokeColor">@color/dark_blue</item>
</style>
<style name="Theme.MyApp.Toggle.NotSelected" parent="Widget.MaterialComponents.Button.OutlinedButton">
<item name="android:checked">false</item>
<item name="backgroundTint">@color/white</item>
<item name="android:textColor">@color/dark_blue</item>
<item name="strokeColor">@color/dark_blue</item>
</style>
When either button is selected, I am trying to essentially swap the styles by having the Fragment this lives on using an Observer
to watch for a property change on the ViewModel so it can flip the styles. The ViewModel side works fine, but swapping styles does not. The code for changing styles looks like this:
val btnCases = binding.root.findViewById<MaterialButton>(R.id.btnCases)
val btnUnits = binding.root.findViewById<MaterialButton>(R.id.btnUnits)
when (it) {
ScanningModes.CASE -> {
btnCases.setTextAppearance(R.style.Theme_MyApp_Toggle_Selected)
btnUnits.setTextAppearance(R.style.Theme_MyApp_Toggle_NotSelected)
}
ScanningModes.UNIT -> {
btnUnits.setTextAppearance(R.style.Theme_MyApp_Toggle_Selected)
btnCases.setTextAppearance(R.style.Theme_MyApp_Toggle_NotSelected)
}
}
The desired result is to flip the styles completely, but after a lot of trial and error (which got me to the above), what ends up happening is when Cases is selected (on initial load and by flipping back and forth between it and Units), I get this (desired result):
However, when I select Units, it does this:
This seems like it should be fairly easy to do, but I'm at a loss on how to accomplish this and hoping someone can assist.
Thanks in advance!
Upvotes: 0
Views: 595
Reputation: 364371
You don't need to switch style. You can just use one style with some selectors defining the android:state_checked
state.
Something like:
<style name="App.Material3.Button.OutlinedButton" parent="Widget.Material3.Button.OutlinedButton">
<item name="backgroundTint">@color/app_m3_text_button_background_color_selector</item>
<item name="strokeColor">@color/app_button_outline_color_selector</item>
<item name="android:textColor">@color/app_text_button_foreground_color_selector</item>
</style>
with app_m3_text_button_background_color_selector
:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/teal_200" android:alpha="0.12"
android:state_enabled="true" android:state_checked="true"/>
<item android:color="?attr/colorContainer"/>
</selector>
app_button_outline_color_selector
:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="0.12" android:color="?attr/colorOnSurface" android:state_enabled="false" />
<item android:alpha="0.12" android:color="@color/blu500_dark" android:state_enabled="true" android:state_checked="true"/>
<item android:color="?attr/colorOutline" />
</selector>
app_text_button_foreground_color_selector
:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Disabled -->
<item android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorOnSurface" android:state_enabled="false" />
<!-- Uncheckable -->
<item android:color="?attr/colorOnContainer" android:state_checkable="false" />
<!-- Checked Buttons. -->
<item android:color="@color/blu500_dark" android:state_checked="true" />
<!-- Not-checked Buttons. -->
<item android:color="?attr/colorOnSurface" />
</selector>
Upvotes: 4
Reputation: 2475
After reviewing some additional details, I ended up solving the immediate problem by using setTextAppearance
and setBackgroundColor
since those are all I was really trying to change anyway. End result was this:
val btnCases = binding.root.findViewById<MaterialButton>(R.id.btnCases)
val btnUnits = binding.root.findViewById<MaterialButton>(R.id.btnUnits)
when (it) {
ScanningModes.CASE -> {
//change the text styles
btnCases.setTextAppearance(R.style.Theme_MyApp_Toggle_Selected)
btnUnits.setTextAppearance(R.style.Theme_MyApp_Toggle_NotSelected)
//change the background colors
btnCases.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.dark_blue))
btnUnits.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
}
ScanningModes.UNIT -> {
btnUnits.setTextAppearance(R.style.Theme_MyApp_Toggle_Selected)
btnCases.setTextAppearance(R.style.Theme_MyApp_Toggle_NotSelected)
//change the background colors
btnUnits.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.dark_blue))
btnCases.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
}
}
It's kind of amazing that changing a style directly isn't supported, but I'm sure there are reasons. Thankfully I didn't have to change more, or I'd have been stuck!
Upvotes: 0