如何使用数据绑定在 checkChanged 事件上绑定 RadioGroup 上的方法

How to bind method on RadioGroup on checkChanged event with data-binding

我在互联网上搜索如何在 RadioGroup 上执行新的很酷的 android 数据绑定,但我没有找到关于它的博客 post。

这是一个简单的场景,基于所选的单选按钮,我想使用 android 数据绑定附加一个回调事件。我在 xml 部分找不到任何允许我定义回调的方法。

这里是我的 RadioGroup:

      <RadioGroup
            android:id="@+id/split_type_radio"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:checkedButton="@+id/split_type_equal"
            android:gravity="center"
            <!-- which tag ? -->
            android:orientation="horizontal">

           ...

       </RadioGroup>

如何附加将在 RadioGroupcheckChnged 事件上使用数据绑定调用的处理程序方法?

我尝试在布局文件中使用 onClick(不知道是否相同)并在 Activity 中定义方法并在布局文件中使用它定位它:

   <variable
        name="handler"
        type="com.example.MainActivity"/>

  ...
   <RadioGroup
        android:onClick="handler.onCustomCheckChanged"
        .. >

并像这样定义方法 onCustomCheckChanged

public void onCustomCheckChanged(RadioGroup radio, int id) {
     // ...
}

但是,它给我编译错误:

Error:(58, 36) Listener class android.view.View.OnClickListener with method onClick did not match signature of any method handler.onCustomCheckChanged

我看到很多博客提到 RadioGroup 是可能的,但没有一个真正说明如何。我该如何处理 data-binding

在深入研究了一堆方法之后,我在 SO 上发现了 个问题,它帮助我理解了如何绑定监听器的单个方法。

以下是如何处理 RadioGroup:

RadioGroup 侦听器中,您有一个方法 onCheckedChanged(RadioGroup g, int id)。因此,您可以通过将该方法的实例作为布局文件中的变量传递并调用具有相同签名的方法,直接将该方法绑定到您的处理程序或 activity。

所以像这样调用布局文件:

  <RadioGroup
        android:id="@+id/split_type_radio"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:checkedButton="@+id/split_type_equal"
        android:gravity="center"
        android:onCheckedChanged="@{handler.onSplitTypeChanged}"
        android:orientation="horizontal">

       ...

   </RadioGroup>

并且在我的 activity 或处理程序中,我需要简单地提供具有相同名称和签名的方法,如下所示:

public void onSplitTypeChanged(RadioGroup radioGroup,int id) {
  // ...
}

只需确保方法是 public。

注意: 这适用于任何(大多数,我还没有尝试过所有)侦听器方法。像 EditText 你可以提供 android:onTextChanged 等等。

我正在使用一个字符串,在这种情况下,我有基于 viewModel.getCommuteType() viewModel.setCommuteType(String)

的可绑定
<RadioGroup
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<RadioButton
    android:checked="@{viewModel.commuteType.equals(Commute.DRIVING)}"
    android:onClick="@{()->viewModel.setCommuteType(Commute.DRIVING)}"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="D"/>

<RadioButton
    android:checked="@{viewModel.commuteType.equals(Commute.BICYCLE)}"
    android:onClick="@{()->viewModel.setCommuteType(Commute.BICYCLE)}"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="B"/>

<RadioButton
    android:checked="@{viewModel.commuteType.equals(Commute.WALKING)}"
    android:onClick="@{()->viewModel.setCommuteType(Commute.WALKING)}"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="W"/>

<RadioButton
    android:checked="@{viewModel.commuteType.equals(Commute.BUS)}"
    android:onClick="@{()->viewModel.setCommuteType(Commute.BUS)}"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="T"/>

通常您更关心 实际检查了什么 而不是 "something was checked"。在这种情况下,替代解决方案是忽略 RadioGroup 并绑定所有项目,如下所示:

<RadioGroup (...) >
        <RadioButton (...)
            android:checked="@={viewModel.optionA}"/>

        <RadioButton (...)
            android:checked="@={viewModel.optionB}"/>

        <RadioButton (...)
            android:checked="@={viewModel.optionC}"/>
</RadioGroup>

其中 optionA、optionB 和 optionC 在 ViewModel 中定义如下:

public final ObservableBoolean optionA = new ObservableBoolean();
public final ObservableBoolean optionB = new ObservableBoolean();
public final ObservableBoolean optionC = new ObservableBoolean();

这通常就足够了,但是如果您想在点击时立即做出反应,那么您可以添加回调并像这样使用它们:

OnPropertyChangedCallback userChoosedA = new OnPropertyChangedCallback() {
    @Override
    public void onPropertyChanged(Observable sender, int propertyId) {
        (...) // basically propertyId can be ignored in such case
    }
};

optionA.addOnPropertyChangedCallback(userChoosedA);

这种方法的优点是您不需要比较和跟踪 "id"。

在我现在的项目中,我是这样做的。 我在项目中有三种货币,我通过 RadioGroup 选择其中一种。

它是货币枚举:

enum class Currency(val value: Byte) {
    USD(0),
    EUR(1),
    RUB(2);

    companion object Create {
        fun from(sourceValue: Byte): Currency = values().first { it.value == sourceValue }
        fun from(sourceValue: String): Currency = values().first { it.toString() == sourceValue }
    }
}

我的 ViewModel 的一部分:

    class BaseCurrencyViewModel : ViewModelBase<BaseCurrencyModelInterface>() {
        /**
         * Selected currency
         */
        val currency: MutableLiveData<Currency> = MutableLiveData()

        /**
         *
         */
        init {
            currency.value = Currency.USD   // Init value
        }
  }

我的部分布局(注意绑定在RadioGroup和RadioButton的标签):

<RadioGroup
    android:id="@+id/currencySwitchers"

    android:layout_width="wrap_content"
    android:layout_height="wrap_content"

    app:selectedCurrency = "@{viewModel.currency}"

    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintHorizontal_bias="0.5"
    app:layout_constraintEnd_toEndOf="parent">

    <RadioButton
        android:id="@+id/usdSwitcher"

        android:text="USD"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"

        android:tag="USD"
    />

    <RadioButton
        android:id="@+id/eurSwitcher"

        android:text="EUR"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"

        android:tag="EUR"
    />

    <RadioButton
        android:id="@+id/rubSwitcher"

        android:text="RUB"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"

        android:tag="RUB"
    />
</RadioGroup>

最后一部分 - 绑定适配器。

@BindingAdapter("selectedCurrency")
fun setSelectedCurrency(view: View, value: MutableLiveData<Currency>?) {
    view.getParentActivity()?.let { parentActivity ->
        value?.observe(parentActivity, Observer { value ->
            view.findViewWithTag<RadioButton>(value.toString())
                ?.also {
                    if(!it.isChecked) {
                        it.isChecked = true
                    }
                }
            }
        )

        (view as RadioGroup).setOnCheckedChangeListener { radioGroup, checkedId ->
            val currency = Currency.from(radioGroup.findViewById<RadioButton>(checkedId).tag as String)
            if(value != null && value.value != currency) {
                value.value = currency
            }
        }
    }
}

通过这种方式,我在我的 ViewModel 中获得了 RadioGroup 和 属性 之间的双向绑定。

几个小时后,我找到了简单的方法:android 中的双向数据绑定。它是 和 Kotlin 的基本框架。您也可以使用 ObservableField()

  1. 将您的设置为数据
  2. 使用您喜欢的按钮创建您的 。重要:设置所有单选按钮 id!!!
  3. 在您的无线电组中设置双向 以检查变量(使用 viewmodel 变量)
  4. 享受)

layout.xml

<data>
    <variable
        name="VM"
        type="...YourViewModel" />
</data>


<LinearLayout
            android:id="@+id/settings_block_env"
            ...
            >


            <RadioGroup

                android:id="@+id/env_radioGroup"
                android:checkedButton="@={VM.radio_checked}">

                <RadioButton
                    android:id="@+id/your_id1"/>

                <RadioButton
                   android:id="@+id/your_id2" />

                <RadioButton
                    android:id="@+id/your_id3"/>

                <RadioButton
                    android:id="@+id/your_id4"/>
            </RadioGroup>

        </LinearLayout>

class YourViewModel(): ViewModel {

var radio_checked = MutableLiveData<Int>()


init{
    radio_checked.postValue(R.id.your_id1)//def value
}

//other code
}