1
votes

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
The view can keep the state if the fragment is on the stack and was not destroyed. I don;t understand what do you mean that is has reset, what do you mean by that? - baltekg
What I mean by reset is that toggleButton.isChecked = false (the default state), while the view is showing the drawable for the ON (toggleButton.isChecked = true) state. I am using view binding and in the debugger I see that toggleButton view is retained between fragments. What I am not getting is why, if the view is retained, is toggleButton.isChecked = false when the view is still showing ON state. - Knight Forked
If you could provide some code where you bind the view that would be awesome. - baltekg
I have added the binding code to the original question. - Knight Forked

2 Answers

0
votes

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
votes

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)
}