How To Perform Two-way Data Binding With A Togglebutton?
Solution 1:
You need another '=' to tell Android that you want to use Two-Way databinding:
android:checked="@={activity.editing}"
You can find more information on this in the wordpress article of George Mount:
Two-Way Data Binding
Android isn’t immune to typical data entry and it is often important to reflect changes from the user’s input back into the model. For example, if the above data were in a contact form, it would be nice to have the edited text pushed back into the model without having to pull the data from the EditText. Here’s how you do it:
<layout...><data><variabletype="com.example.myapp.User"name="user"/></data><RelativeLayout...><EditTextandroid:text="@={user.firstName}".../></RelativeLayout></layout>
Pretty nifty, eh? The only difference here is that the expression is marked with
@={}
instead of@{}
. It is expected that most data binding will continue to be one-way and we don’t want to have all those listeners created and watching for changes that will never happen.
Solution 2:
No need to take ObservableBoolean
, you can perform this operation by regular getter-setter method of boolean variable. Like this in your model class
publicclassUser{
privateboolean checked;
publicbooleanisChecked() {
return checked;
}
publicvoidsetChecked(boolean checked) {
this.checked = checked;
}
}
perform Two-way binding on your ToggleButton
.
<ToggleButtonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:checked="@={user.checked}"/>
and fetch this value by using binding variable.
binding.getUser().isChecked()
Solution 3:
Here's a simple example of a 2-way databinding using a Switch, which also has the Checked property, like the ToggleButton.
Item.java:
import android.databinding.BaseObservable;
import android.databinding.Bindable;
publicclassItemextendsBaseObservable {
privateBoolean checked;
@BindablepublicBooleangetChecked() {
returnthis.checked;
}
publicvoidsetChecked(Boolean checked) {
this.checked = checked;
notifyPropertyChanged(BR.checked);
}
}
MainActivity.java:
publicclassMainActivityextendsAppCompatActivity {
publicItem item;
ActivityMainBinding binding;
@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
item = newItem();
item.setChecked(true);
/* By default, a Binding class will be generated based on the name of the layout file,
converting it to Pascal case and suffixing “Binding” to it.
The above layout file was activity_main.xml so the generate class was ActivityMainBinding */
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setItem(item);
}
publicvoidbutton_onClick(View v) {
item.setChecked(!item.getChecked());
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?><layoutxmlns:android="http://schemas.android.com/apk/res/android"><data><variablename="item"type="com.example.abc.twowaydatabinding.Item" /></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><Switchandroid:id="@+id/switch_test"android:layout_width="wrap_content"android:layout_height="wrap_content"android:checked="@={item.checked}" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="change"android:onClick="button_onClick"/></LinearLayout></layout>
build.gradle:
android {
...
dataBinding{
enabled=true
}
}
Source documentation: https://developer.android.com/topic/libraries/data-binding/index.html
Solution 4:
Here are ways to set OnCheckedChangeListener
in data binding:
(1) Set by method expression
In layout
<variablename="activity"type="com.innovanathinklabs.sample.activities.CalendarActivity"/><ToggleButtonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:checked="@={model.checked}"android:onCheckedChanged="@{activity::onGenderChanged}"
/>
In Activity
classHomeActivity : AppCompatActivity() {
overridefunonCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityCalendarBinding>(this, R.layout.activity_calendar)
binding.activity = this
binding.model = Model()
}
funonGenderChanged(buttonView: CompoundButton, isChecked: Boolean) {
println("buttonView = [$buttonView], isChecked = [$isChecked]")
}
}
(2) Set by lambda expression and method call
<variablename="model"type="com.innovanathinklabs.sample.data.Model"/><variablename="activity"type="com.innovanathinklabs.sample.activities.HomeActivity"/><ToggleButtonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:checked="@={model.checked}"android:onCheckedChanged="@{(button, bool)-> activity.saveGender(bool)}"
/>
In Activity
classHomeActivity : AppCompatActivity() {
overridefunonCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityCalendarBinding>(this, R.layout.activity_calendar)
binding.activity = this
binding.model = Model()
}
funsaveGender(isChecked: Boolean) {
println("isChecked = [$isChecked]")
}
}
(3) Pass OnCheckedChangeListener
anonymous class to layout
<variablename="onGenderChange"type="android.widget.CompoundButton.OnCheckedChangeListener"/><ToggleButtonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:checked="@={model.checked}"android:onCheckedChanged="@{onGenderChange}"
/>
In Activity
classHomeActivity : AppCompatActivity() {
overridefunonCreate(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
<variablename="onGenderChange2"type="android.widget.CompoundButton.OnCheckedChangeListener"/><ToggleButtonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:checked="@={model.checked}"android:onCheckedChanged="@{onGenderChange2}"
/>
Activity
classHomeActivity : AppCompatActivity() {
overridefunonCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityCalendarBinding>(this, R.layout.activity_calendar)
binding.model = Model()
binding.onGenderChange2 = onGenderChange
}
privateval onGenderChange: CompoundButton.OnCheckedChangeListener = CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
println("buttonView = [$buttonView], isChecked = [$isChecked]")
}
}
This will never work
Because you can't set two callback on one component. One callback is already set by two way binding, so your callback will not work.
binding.toggleButton.setOnCheckedChangeListener { buttonView, isChecked ->
println("buttonView = [$buttonView], isChecked = [$isChecked]")
}
Check CompoundButtonBindingAdapter class to see how Switch Binding works.
Post a Comment for "How To Perform Two-way Data Binding With A Togglebutton?"