web-dev-qa-db-ja.com

データバインディングでcheckChangedイベントのRadioGroupにメソッドをバインドする方法

新しいクールな方法をインターネットで検索していましたAndroid RadioGroupを介したデータバインディングですが、それに関するブログの投稿は1つも見つかりませんでした。

選択したラジオボタンに基づいたその単純なシナリオで、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(同じかどうかわからない)を使用してアクティビティのメソッドを定義し、レイアウトファイルでこれを使用して配置しました。

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

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

そして、次のようにメソッドonCustomCheckChangedを定義しました:

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

しかし、それは私にコンパイルエラーを与えます:

エラー:(58、36)メソッドonClickを持つリスナークラスAndroid.view.View.OnClickListenerは、どのメソッドハンドラーのシグネチャとも一致しませんでした。onCustomCheckChanged

私はRadioGroupでそれが可能であると述べている多くのブログを見てきましたが、それらのどれも実際に方法を述べていません。これをdata-bindingでどのように処理できますか?

11
kirtan403

メソッドの束を掘り下げた後、私は this の質問をSOで見つけました。リスナーの単一のメソッドをバインドする方法を理解するのに役立ちました。

RadioGroupをどうするかを次に示します。

RadioGroupリスナーには、メソッドonCheckedChanged(RadioGroup g, int id)があります。そのため、レイアウトファイルで変数のインスタンスを渡し、同じシグネチャでメソッドを呼び出すことにより、そのメソッドをハンドラーまたはアクティビティに直接バインドできます。

したがって、次のようなレイアウトファイルを呼び出します。

  <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>

そして、私のアクティビティまたはハンドラーで、次のように同じ名前とシグネチャを持つメソッドを提供する必要があります。

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

メソッドがパブリックであることを確認してください。

注:これは、(ほとんどの場合、私はすべてを試したわけではありませんが)すべてのリスナーメソッドで機能します。 EditTextと同様に、Android:onTextChanged 等々。

15
kirtan403

私は文字列を使用しており、この場合は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"/>
11
Juan Mendez

数時間後、私は簡単な方法を見つけました。Androidでの双方向データバインディングです。 livedata とKotlinの基本スケルトンです。また、ObservableField()を使用することもできます

  1. viewmodel をデータに設定します
  2. radiogroup をボタンで作成します。重要:すべてのラジオボタン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
}
8
Serega Maleev

whatが「チェックされたもの」ではなく実際にチェックされたことを気にすることがよくあります。このような場合の代替ソリューションは、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();

通常はこれで十分ですが、クリックですぐに反応したい場合は、callBackを追加して、次のように使用できます。

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

optionA.addOnPropertyChangedCallback(userChoosedA);

このようなアプローチの利点は、「id」を比較して追跡する必要がないことです。

3
LLL

現在のプロジェクトでは、このようにしました。プロジェクトには3つの通貨があり、RadioGroupを介してそのうちの1つを選択します。

それは通貨の列挙型です:

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
            }
        }
    }
}

このようにして、RadioGroupとViewModelのプロパティとの間で双方向バインディングを取得しました。

1
Alex Shevelev