Toggle Button View Retains State

199 views Asked by At

In one of my App's fragments the layout uses a toggle button defined as:

<ToggleButton
    android:id="@+id/custom_toggle_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_marginStart="4dp"
    android:minWidth="110dp"
    android:minHeight="36dp"
    android:background="@drawable/toggle_button_bg_bw"
    android:textColor="@drawable/toggle_color_bw"
    android:textOff="@string/text_off"
    android:textOn="@string/text_on"
    android:textSize="12sp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toEndOf="@id/stm"
    app:layout_constraintTop_toTopOf="parent" />

Background drawable:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
            android:drawable="@drawable/black_button_selected"
            android:state_checked="true" />
    <item
            android:drawable="@drawable/white_button_unselected" />
</selector>

black_button_selected:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle" >
    <stroke
            android:width="2dp"
            android:color="@color/colorGreen" />
    <solid
            android:color="@color/colorBlack" />
    <corners android:radius="3dp" />
</shape>

white_button_unselected:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle" >
    <stroke
            android:width="2dp"
            android:color="@color/colorGreen" />
    <solid
            android:color="@color/colorWhite" />
    <corners android:radius="3dp" />
</shape>

TextColor drawable:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
            android:state_checked="false"
            android:color="@color/colorBlack" />
    <item
            android:state_checked="true"
            android:color="@color/colorWhite" />
</selector>

In createView following code is called. options_view contains other buttons and view elements, which is attached to editorView and editorView is a part of this fragment layout.

optionsViewBinding = DataBindingUtil.inflate(
    inflater,
    R.layout.options_view,
    binding.editorView,
    true
)

optionsViewBinding.run {
    customToggleButton.isChecked = false
    customToggleButton.setOnClickListener {
        someFunction(customToggleButton.isChecked)
    }
}

Problem I am facing is, when I toggle the switch to 'on' and move on to some other fragment and come back to fragment with this toggle button, while the state of the toggle button has reset to 'false'/OFF state and yet the view on display shows it in its 'on' state.

What am I missing here?

2

There are 2 answers

2
baltekg On

You could try a few diferrent things but I dont guarantee they will work.
I personally try to avoid setting things in onCreateView, because views are not always created there. The problem could be that you change the state of the button before the view is fully initialized and it then kind of overrides the state of the ToggleButton so you have certain state set and wrong view. So put this lines in OnViewCreated:

customToggleButton.isChecked = false
customToggleButton.setOnClickListener {
    someFunction(customToggleButton.isChecked)
}

Also, if you can leave the toggleButtonstate when you change fragments, you could just omit below line and it should be keeping the state fine and the background showing should be correct:

customToggleButton.isChecked = false
0
Knight Forked On

I have not been able to solve this issue, however I have been able to work out an alternative, it may not be the most elegant alternative but it works.

Create a custom button class:

class CustomToggleButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : AppCompatButton(context, attrs, defStyleAttr) {
    var isChecked = false
    var onOffResID = Array<Int>(2) { 0 }
    var onOffTextColorId = Array<Int>(2) { 0 }

    fun initButton() {
        // Should crash if resource ID invalid
        background = AppCompatResources.getDrawable(context, onOffResID[0])
        setTextColor(context.resources.getColor(onOffTextColorId[0]))
    }

    fun onClick() {
        isChecked = !isChecked
        val index = if (isChecked) 1 else 0
        background = AppCompatResources.getDrawable(context, onOffResID[index])
        setTextColor(context.resources.getColor(onOffTextColorId[index]))
    }
}

In fragment onCreateView or onViewCreated:

customToggleButton.onOffResID = arrayOf(R.drawable.white_button_unselected, R.drawable.black_button_selected)
customToggleButton.onOffTextColorId = arrayOf(R.color.colorBlack, R.color.colorWhite)
customToggleButton.initButton()
customToggleButton.setOnClickListener {
    customToggleButton.onClick()
    someFunction(customToggleButton.isChecked)
}