新しいクールな方法をインターネットで検索していました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>
RadioGroup
のcheckChnged
イベントで呼び出されるハンドラーメソッドをデータバインディングを使用して起動するにはどうすればよいですか?
レイアウトファイルで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
でどのように処理できますか?
メソッドの束を掘り下げた後、私は 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
等々。
私は文字列を使用しており、この場合は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"/>
数時間後、私は簡単な方法を見つけました。Androidでの双方向データバインディングです。 livedata とKotlinの基本スケルトンです。また、ObservableField()を使用することもできます
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
}
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つの通貨があり、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のプロパティとの間で双方向バインディングを取得しました。