androidmaterial-designmaterial-design-3

Material Design 3 MaterialSwitch used in include layout does not change visual state


The Material Design 3 MaterialSwitch used in include layout does not change visual state when tap or slide to the right.

Condsider what happens, when I tap or slide the enabled Material Switch: MaterialSwitch unchecked state MaterialSwitch checked state

Notice that the position and color of the slide track is not what it should appear as according to the documented expected behavior.

The thumb icon will change, but the thumb will not slide to the right with a change in track color. (This is not built-in behavior, but it made it obvious that something was not working.)

It is confirmed that the isChecked Boolean value of the MaterialSwitch does change from false to true (Android Studio log).

Reusable include layout standard_include_layout.xml:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable name="wasChecked" type="Boolean" />
    </data>

    <com.google.android.material.materialswitch.MaterialSwitch
        android:id="@+id/check_switch"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:enabled="true"
        android:checked="@={wasChecked}" />
...

Include standard_include_layout.xml in Fragment's layout XML:

...
<include
    android:id="@+id/includedLayout"
    layout="@layout/standard_include_layout"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:wasChecked="@={viewmodel.wasChecked}" />
...

Set the icon state in Fragment:

   override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
...
        viewModel.wasChecked.observe(viewLifecycleOwner) {
            includedLayout.checkSwitch.isChecked = it
            if (it == true)
                checkSwitch.thumbIconDrawable =  AppCompatResources.getDrawable(context, R.drawable.ic_checkmark)
            else checkSwitch.thumbIconDrawable = null
        }

ViewModel LiveData val referenced:

    val wasChecked = MutableLiveData<Boolean>().apply {
        value = false
    }

If a include layout is not involved. Everything, works as documented. Tap or slide to the right will change the position of the slide thumb, change the color of the track, and set the thumb icon.

Any idea what is wrong?


Solution

  • Attaching setOnCheckedChangeListener programmatically, instead of observing the binding val for a change will work.

    includedLayout.checkSwitch.setOnCheckedChangeListener { buttonView, isChecked ->
        viewModel.wasChecked.value = isChecked
    
        // To-do: Figure out how to change the thumb icon here, if it's even possible; using buttonView did not work.
    }
    
    // Workaround for being unable to set thumb icon within setOnCheckedChangeListener.
    viewModel.wasChecked.observe(viewLifecycleOwner) {
        // Set thumb icon.
        if (isChecked == true)
            aMaterialSwitch.thumbIconDrawable =
                AppCompatResources.getDrawable(requireContext(), R.drawable.ic_checkmark)
        else
            aMaterialSwitch.thumbIconDrawable = null
    }