44

As question indicates, how to bind checked change listener to Switch button in xml ?

I am not using recycler view. Just a simple layout.

Any help appreciated.

Khemraj Sharma
  • 57,232
  • 27
  • 203
  • 212
Mohanish Nerurkar
  • 541
  • 1
  • 5
  • 10

4 Answers4

52

Using lambda expression and a Switch:

public void onCheckedChanged(boolean checked) {
     // implementation      
}

XML file:

<android.support.v7.widget.SwitchCompat
    android:onCheckedChanged="@{(switch, checked) -> item.onCheckedChanged(checked)}"
    ...
/>

Where item is the class that implements onCheckedChange method and is imported to the XML file like this:

<data>
    <variable
        name="item"
        type="yourClass"/>
</data>
tomrozb
  • 25,773
  • 31
  • 101
  • 122
29

Different Ways

(1) Set by method expression

In layout

<variable
    name="activity"
    type="com.innovanathinklabs.sample.activities.CalendarActivity"/>

<Switch
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:checked="@={model.checked}"
    android:onCheckedChanged="@{activity::onGenderChanged}"
    />

In Activity

class HomeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = DataBindingUtil.setContentView<ActivityCalendarBinding>(this, R.layout.activity_calendar)
        binding.activity = this
        binding.model = Model()
    }

    fun onGenderChanged(buttonView: CompoundButton, isChecked: Boolean) {
        println("buttonView = [$buttonView], isChecked = [$isChecked]")
    }
}

(2) Set by lambda expression and method call

<variable
    name="model"
    type="com.innovanathinklabs.sample.data.Model"/>

<variable
    name="activity"
    type="com.innovanathinklabs.sample.activities.HomeActivity"/>

<Switch
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:checked="@={model.checked}"
    android:onCheckedChanged="@{(button, bool)-> activity.saveGender(bool)}"
    />

In Activity

class HomeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = DataBindingUtil.setContentView<ActivityCalendarBinding>(this, R.layout.activity_calendar)
        binding.activity = this
        binding.model = Model()
    }

    fun saveGender(isChecked: Boolean) {
        println("isChecked = [$isChecked]")
    }
}

(3) Pass OnCheckedChangeListener anonymous class to layout

<variable
    name="onGenderChange"
    type="android.widget.CompoundButton.OnCheckedChangeListener"/>

<Switch
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:checked="@={model.checked}"
    android:onCheckedChanged="@{onGenderChange}"
    />

In Activity

class HomeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = DataBindingUtil.setContentView<ActivityCalendarBinding>(this, R.layout.activity_calendar)
        binding.model = Model()
        binding.setOnGenderChange { buttonView, isChecked ->
            println("buttonView = [$buttonView], isChecked = [$isChecked]")
        }
    }
}

(4) Pass OnCheckedChangeListener by reference

<variable
    name="onGenderChange2"
    type="android.widget.CompoundButton.OnCheckedChangeListener"/>

<Switch
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:checked="@={model.checked}"
    android:onCheckedChanged="@{onGenderChange2}"
    />

Activity

class HomeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = DataBindingUtil.setContentView<ActivityCalendarBinding>(this, R.layout.activity_calendar)
        binding.model = Model()
        binding.onGenderChange2 = onGenderChange
    }

    private val onGenderChange: CompoundButton.OnCheckedChangeListener = CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
        println("buttonView = [$buttonView], isChecked = [$isChecked]")
    }
}

Now below will NOT work

Now if you set CheckChangeListener in code that will not work. because you can't set two callback on one component. One callback is already set by binding, so your callback in code will not work.

binding.mySwitch.setOnCheckedChangeListener { buttonView, isChecked ->
    println("buttonView = [$buttonView], isChecked = [$isChecked]")
}

Check CompoundButtonBindingAdapter class to see how Switch Binding works.

Khemraj Sharma
  • 57,232
  • 27
  • 203
  • 212
  • The last statement saved my day. Apparently I had 2 listeners on a RadioGroup and was wondering why the binding implementation wasn't working – Danilo Mz Nov 20 '18 at 09:17
  • Is there a way to do this just using xml? I.e. if I have a SwitchPreference in an xml and I want it to use a custom layout `android:layout="@layout/custom"` and pass that layout a data-bound title "passedTitle", I can do it successfully using as follows: ``, but it doesn't do anything (I get `attribute passedTitle not found`) if I just do it in the preference: ` – Elliptica May 01 '19 at 08:52
  • 1
    Beautiful answer.used the last one – kgandroid Jun 29 '20 at 12:28
  • To bad, I can't give plus one for each solution you submitted. – Shawn Sep 25 '20 at 23:03
  • you don't need to reference activity, `android:onCheckedChanged` should trigger a request in viewModel – user924 Aug 12 '22 at 08:39
13

You can do it with a method reference:

<CheckBox android:onCheckedChanged="@{callback::checkedChangedListener}".../>

or with a lambda expression if you want to pass different parameters:

<CheckBox android:onCheckedChanged="@{() -> callback.checked()}".../>
tomrozb
  • 25,773
  • 31
  • 101
  • 122
George Mount
  • 20,708
  • 2
  • 73
  • 61
4

Simply use ViewModel, liveData and Transformations first on your ViewModel

var availabilityState = MutableLiveData<Boolean>(false)
val availabilityText :LiveData<String> =Transformations.map(availabilityState)
{
    if (it == true)
    {
        "Available"
    }else
    {
      "Not Available"
    }
}

Then on your XML use

<Switch
android:checked="@={addBookViewModel.availabilityState}"
android:text="@{addBookViewModel.availabilityText}"
...>

That is it.

Khaled Mahmoud
  • 285
  • 2
  • 7