Как выполнить двустороннюю привязку данных с помощью ToggleButton?

у меня естьObservableBoolean поле в моем классе активности, которое связано с атрибутом «флажок» моегоToggleButton вот так:

android:checked="@{activity.editing}"

Я надеялся, что это создаст двустороннюю связь между кнопкой и логическим значением, но он переносит только изменения с поля на кнопку, а не наоборот. Что я делаю не так, или это не входит в сферу AndroidDataBinding?

Ответы на вопрос(4)

Вот способы установитьOnCheckedChangeListener в привязке данных:

(1) устанавливаетсяметод выражения

В макете

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

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

В деятельности

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) устанавливаетсялямбда-выражение и вызов метода
<variable
    name="model"
    type="com.innovanathinklabs.sample.data.Model"/>

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

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

В деятельности

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) пройтиOnCheckedChangeListener анонимный класс для макета
<variable
    name="onGenderChange"
    type="android.widget.CompoundButton.OnCheckedChangeListener"/>

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

В деятельности

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) пройтиOnCheckedChangeListener по ссылке
<variable
    name="onGenderChange2"
    type="android.widget.CompoundButton.OnCheckedChangeListener"/>

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

Деятельность

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]")
    }
}
Это никогда не сработает

Потому что вы не можете установить два обратных вызова на один компонент. Один обратный вызов уже установлен двусторонним связыванием, поэтому ваш обратный вызов не будет работать.

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

ПроверьтеCompoundButtonBindingAdapter учебный класс чтобы увидеть, как работает Switch Binding.

h, который также имеет свойство Checked, такое как ToggleButton.

Item.java:

import android.databinding.BaseObservable;
import android.databinding.Bindable;

public class Item extends BaseObservable {
    private Boolean checked;
    @Bindable
    public Boolean getChecked() {
        return this.checked;
    }
    public void setChecked(Boolean checked) {
        this.checked = checked;
        notifyPropertyChanged(BR.checked);
    }
}

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    public Item item;
    ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        item = new Item();
        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);
    }

    public void button_onClick(View v) {
        item.setChecked(!item.getChecked());
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="item"
            type="com.example.abc.twowaydatabinding.Item" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <Switch
            android:id="@+id/switch_test"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:checked="@={item.checked}" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="change"
            android:onClick="button_onClick"/>

    </LinearLayout>
</layout>

build.gradle:

android {
...
    dataBinding{
        enabled=true
    }

}

Исходная документация:https://developer.android.com/topic/libraries/data-binding/index.html

Решение Вопроса

=', чтобы сообщить Android, что вы хотите использовать двустороннюю привязку данных:

android:checked="@={activity.editing}"

Вы можете найти больше информации об этомв WordPress статье Джорджа Маунта:

Двухстороннее связывание данных

Android не защищен от типичного ввода данных, и часто важно отразить изменения от ввода пользователя обратно в модель. Например, если вышеупомянутые данные были в контактной форме, было бы хорошо, чтобы отредактированный текст был перенесен обратно в модель без необходимости извлечения данных из EditText. Вот как вы это делаете:

<layout ...>
    <data>
        <variable type="com.example.myapp.User" name="user"/>
    </data>
    <RelativeLayout ...>
        <EditText android:text="@={user.firstName}" .../>
    </RelativeLayout>
</layout>

Довольно изящно, а? Единственная разница здесь в том, что выражение помечено@={} вместо@{}, Ожидается, что большая часть привязки данных будет по-прежнему односторонней, и мы не хотим, чтобы все эти слушатели создавались и следили за изменениями, которые никогда не произойдут.

 Amit Bhandari03 апр. 2018 г., 13:45
этот ответ золотой

Не нужно братьObservableBooleanВы можете выполнить эту операцию обычным методом getter-setter логической переменной. Как это в вашем классе модели

public class User{
   private boolean checked;

   public boolean isChecked() {
       return checked;
   }

   public void setChecked(boolean checked) {
       this.checked = checked;
   }
}

выполнить двустороннее связывание на вашемToggleButton.

<ToggleButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:checked="@={user.checked}"/>

и получить это значение, используя переменную связывания.

binding.getUser().isChecked()
 saiyancoder29 авг. 2017 г., 05:33
Вы скучаете по@Bindable аннотации в вашемisChecked() иnotifyPropertyChanged(BR.checked) в вашем сеттере.
 Ravi Rupareliya29 авг. 2017 г., 06:21
@saiyancoder Я не думаю, что это необходимо

Ваш ответ на вопрос