web-dev-qa-db-ja.com

ToggleButtonを使用して双方向のデータバインディングを実行する方法

アクティビティクラスにObservableBooleanフィールドがあり、ToggleButtonの「checked」属性にバインドされています。

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

これによりボタンとブール値の間に双方向の関係が作成されることを期待していましたが、フィールドからボタンへの変更のみを保持し、他の方法では保持しません。私は何を間違えていますか、またはこれはAndroid DataBindingの範囲内にありませんか?

22
Gregorio246

双方向データバインディングを使用することをAndroidに伝えるには、別の '='が必要です。

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

詳細については、こちらをご覧ください wordpress George Mountの記事

双方向データバインディング

Androidは通常のデータ入力の影響を受けません。多くの場合、ユーザーの入力からの変更をモデルに反映することが重要です。たとえば、上記のデータが連絡先フォームにある場合、EditTextからデータをプルすることなく、編集したテキストをモデルに押し戻すことができます。方法は次のとおりです。

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

かなり気の利いた、え?ここでの唯一の違いは、式が@={}ではなく@{}でマークされていることです。ほとんどのデータバインディングは一方向であり続けるため、これらのリスナーをすべて作成し、決して発生しない変更を監視することは望ましくありません。

41
yennsarah

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()
5
Ravi Rupareliya

ToggleButtonのようなCheckedプロパティも持つSwitchを使用した2方向のデータバインディングの簡単な例を次に示します。

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

2
live-love

データバインディングで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) lambda expression およびメソッド呼び出しにより設定

<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]")
    }
}

これは機能しません

1つのコンポーネントに2つのコールバックを設定できないためです。 1つのコールバックはすでに双方向バインディングによって設定されているため、コールバックは機能しません。

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

CheckCompoundButtonBindingAdapterclass Switch Bindingの動作を確認します。

1
Khemraj