How to use data binding for Switch onCheckedChageListener event?
Solution 1
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()}".../>
Solution 2
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>
Solution 3
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.
Solution 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.
Mohanish Nerurkar
Updated on July 09, 2022Comments
-
Mohanish Nerurkar almost 2 years
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.
-
Tiago Oliveira over 7 yearsThis is not working for me i get
Unknown attribute android:onCheckedChanged
-
arekolek almost 7 years@TiagoOliveira although I'm also getting that warning, after launching the app it seems to work indeed
-
Aditya Ladwa almost 7 yearsCan we create a custom 2-way binding which would reduce the boilerplate
-
David almost 7 years@GeorgeMount why we can't use app:onCheckedChangeListener to call method setOnCheckedChangeListener in CheckBox?
-
Hossein Shahdoost over 6 years@AdityaLadwa what's wrong with using
checked
attribute? you can bind that pretty easily -
Danilo Mz over 5 yearsThe last statement saved my day. Apparently I had 2 listeners on a RadioGroup and was wondering why the binding implementation wasn't working
-
Elliptica about 5 yearsIs 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 <include> as follows:<include layout="@layout/custom" bind:passedTitle="@{@string/title}" />
, but it doesn't do anything (I getattribute passedTitle not found
) if I just do it in the preference:<SwitchPreference android:key="@string/key" layout="@layout/custom" bind:passedTitle="@{@string/title}"
-
adi about 4 yearsBut after using this, if I try to check my switch programmatically using the binding.mySwitch.setChecked(true), the item.onCheckedChanged method is not getting called !!!
-
kgandroid almost 4 yearsBeautiful answer.used the last one
-
Alessandro Caliaro almost 4 yearsAlso works with androidx.appcompat.widget.SwitchCompat
-
Shawn almost 4 yearsTo bad, I can't give plus one for each solution you submitted.
-
Ajit Kumar Dubey about 3 yearsCannot find a setter for <com.google.android.material.switchmaterial.SwitchMaterial app:onCheckedChanged> that accepts parameter type 'lambda'