I'm learning Kotlin and I'm trying to make two buttons that can be toggled with the following characteristics:
The buttons code:
<ToggleButton
android:id="@+id/button1"
android:background="@color/yellow"
android:text="ToggleButton"
android:textOff="Ton"
android:textOn="Ton"/>
<ToggleButton
android:id="@+id/button2"
android:background="@color/white"
android:text="ToggleButton"
android:textOff="Kg"
android:textOn="Kg"/>
The activity code:
private val btn1 by lazy { findViewById<View>(R.id.button1) as ToggleButton }
private val btn2 by lazy { findViewById<View>(R.id.button2) as ToggleButton }
btn1.setOnClickListener{
btn1.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) { //if btn1 is true he is yellow and btn2 is false and he is white
btn2.isChecked = false
btn1.setBackgroundColor(Color.YELLOW)
btnLoadModeFrac.setBackgroundColor(Color.WHITE)
} else { //if btn1 is false he is white and btn2 is true and he is yellow
btn2.isChecked = true
btn1.setBackgroundColor(Color.WHITE)
btn2.setBackgroundColor(Color.YELLOW)
}
}
}
PROBLEM
The problem here is that, on the first click, I can toggle both button 1 and button 2 (Both are true), even when I set one as false and the other one as true. After that, everything works well.
I tried to set button 1 to true and button 2 to false in my activity before calling the function, but it didn't work either.
Thanks for any help!
I think using OnCheckedChangeListener
to toggle the other button is going to be a difficult way to solve the problem, because when one of the buttons is toggled, it will want to toggle the other, thereby making it want to toggle the other, and so on back and forth.
Since you are changing the color to match a toggle state, it would be more appropriate and robust to handle that with styling. Create a StateListDrawable like this:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/yellow" android:state_checked="true"/>
<item android:drawable="@color/white"/>
</selector>
and set it as the background of both buttons in your layout file rather than the explicit colors.
You'll also want to set one of the buttons to have an initial state of checked:
android:checked="true"
The simple way to have them change each other is to give them each a click listener that toggles the other button.
btn1.setOnClickListener { _ -> btn2.isChecked = !btn2.isChecked }
btn2.setOnClickListener { _ -> btn1.isChecked = !btn1.isChecked }
But in my opinion, it's not good practice to rely on UI elements to store your state if you need these to stay synced. There are UI behaviors that can be finicky (like how quickly double-tapping a Button that starts an Activity can start two copies of that Activity). So I would keep your state stored in a property. You can make it observable so changing it explicitly sets the toggle state of both buttons every time.
private val buttonState by Delegates.observable(true) { _, _, newState ->
btn1.isChecked = newState
btn2.isChecked = !newState
}
//...
val listener = View.OnClickListener { _ -> buttonState = !buttonState }
btn1.onClickListener = listener
btn2.onClickListener = listener