ChipGroup 2路绑定适配器
ChipGroup 2-way binding adapter
我想创建 ChipGroup 2 路绑定适配器。我已经复制了默认的 RadioGroup 绑定适配器并进行了一些更改,但它不适用于这两种方式。在以编程方式将数据设置为可观察的情况下,ChipGroup 从中检索更改。但手动 Chip selection 不会将更改设置为 observable。
这是我的适配器
@InverseBindingMethods(InverseBindingMethod(type = ChipGroup::class, attribute = "android:checkedButton", method = "getCheckedRadioButtonId"))
class ChipGroupBindingAdapter {
companion object {
@JvmStatic
@BindingAdapter("android:checkedButton")
fun setCheckedChip(view: ChipGroup?, id: Int) {
if (id != view?.checkedChipId) {
view?.check(id)
}
}
@JvmStatic
@BindingAdapter(value = ["android:onCheckedChanged", "android:checkedButtonAttrChanged"], requireAll = false)
fun setChipsListeners(view: ChipGroup?, listener: ChipGroup.OnCheckedChangeListener?,
attrChange: InverseBindingListener?) {
if (attrChange == null) {
view?.setOnCheckedChangeListener(listener)
} else {
view?.setOnCheckedChangeListener { group, checkedId ->
listener?.onCheckedChanged(group, checkedId)
attrChange.onChange()
}
}
}
}
}
布局文件:
<android.support.design.chip.ChipGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkedButton="@{viewModel.checkedBtnObs}"
app:singleSelection="true">
<android.support.design.chip.Chip
android:id="@+id/first_chip"
style="@style/Widget.MaterialComponents.Chip.Choice"
android:layout_width="110dp"
android:layout_height="wrap_content"
android:checkable="true"
android:text="@string/month_12"
app:chipBackgroundColor="@drawable/chip_background_selector" />
<android.support.design.chip.Chip
android:id="@+id/second_chip"
style="@style/Widget.MaterialComponents.Chip.Choice"
android:layout_width="110dp"
android:layout_height="wrap_content"
android:checkable="true"
android:text="@string/month_6"
android:textAlignment="center"
app:chipBackgroundColor="@drawable/chip_background_selector" />
<android.support.design.chip.Chip
android:id="@+id/third_chip"
style="@style/Widget.MaterialComponents.Chip.Choice"
android:layout_width="110dp"
android:layout_height="wrap_content"
android:checkable="true"
android:text="@string/month_1"
app:chipBackgroundColor="@drawable/chip_background_selector" />
</android.support.design.chip.ChipGroup>
并且可观察到:
val checkedBtnObs = ObservableInt(R.id.second_chip)
终于,我找到了解决办法。
InverseBindingMethod 方法应该是 getCheckedChipId
而不是 getCheckedRadioButtonId
此外,@=
应该像这样添加到 xml android:checkedButton="@{viewModel.checkedBtnObs}"
android:checkedButton="@={viewModel.checkedBtnObs}"
现在此适配器可用于 ChipGroup 2 向绑定
@InverseBindingMethods(InverseBindingMethod(type = ChipGroup::class, attribute = "android:checkedButton", method = "getCheckedChipId"))
class ChipGroupBindingAdapter {
companion object {
@JvmStatic
@BindingAdapter("android:checkedButton")
fun setCheckedChip(view: ChipGroup?, id: Int) {
if (id != view?.checkedChipId) {
view?.check(id)
}
}
@JvmStatic
@BindingAdapter(value = ["android:onCheckedChanged", "android:checkedButtonAttrChanged"], requireAll = false)
fun setChipsListeners(view: ChipGroup?, listener: ChipGroup.OnCheckedChangeListener?,
attrChange: InverseBindingListener?) {
if (attrChange == null) {
view?.setOnCheckedChangeListener(listener)
} else {
view?.setOnCheckedChangeListener { group, checkedId ->
listener?.onCheckedChanged(group, checkedId)
attrChange.onChange()
}
}
}
}
}
if (attrChange == null) {
view?.setOnCheckedChangeListener(listener)
} else {
view?.setOnCheckedChangeListener { group, checkedId ->
listener?.onCheckedChanged(group, checkedId)
attrChange.onChange()
}
}
}
也许应该
if (listener != null) {
view?.setOnCheckedChangeListener(listener)
} else {
view?.setOnCheckedChangeListener { group, checkedId ->
listener?.onCheckedChanged(group, checkedId)
attrChange.onChange()
}
}
}
我得到了 ChipGroup
,DataBinding
按预期工作并使用 InverseDataBinding
的推荐方式,如果有人想知道,这是我的实现:
SomeBindingAdapters.kt
:
...
object PropertyTypeFilterBindingAdapters {
@BindingAdapter("propertyTypeFilter")
@JvmStatic
fun ChipGroup.bindPropertyTypeFilter(marsApiFilter: MarsApiFilter?) =
marsApiFilter?.let { filter ->
when (filter) {
MarsApiFilter.ALL -> check(R.id.filter_all_properties_chip)
MarsApiFilter.RENT -> check(R.id.filter_properties_for_rent_chip)
MarsApiFilter.BUY -> check(R.id.filter_properties_for_buy_chip)
}
}
@InverseBindingAdapter(attribute = "propertyTypeFilter")
@JvmStatic
fun ChipGroup.convertToMarsApiFilter(): MarsApiFilter = when (checkedChipId) {
R.id.filter_properties_for_rent_chip -> MarsApiFilter.RENT
R.id.filter_properties_for_buy_chip -> MarsApiFilter.BUY
else -> MarsApiFilter.ALL
}
@BindingAdapter("propertyTypeFilterAttrChanged")
@JvmStatic
fun ChipGroup.setListeners(attrChange: InverseBindingListener?) =
setOnCheckedChangeListener { _, _ -> attrChange?.onChange() }
}
...
MarsApiFilter
是针对我的具体情况的枚举 class。
some_layout.xml
:
...
<com.google.android.material.chip.ChipGroup
android:id="@+id/filter_property_type_chip_group"
...
bind:propertyTypeFilter="@={viewModel.propertyTypeFilter}"
>
<com.google.android.material.chip.Chip
android:id="@+id/filter_all_properties_chip"
...
/>
<com.google.android.material.chip.Chip
android:id="@+id/filter_properties_for_rent_chip"
...
/>
<com.google.android.material.chip.Chip
android:id="@+id/filter_properties_for_buy_chip"
...
/>
</com.google.android.material.chip.ChipGroup>
...
bind
只是一个声明为常规名称空间的奇特名称空间:xmlns:bind="http://schemas.android.com/apk/res-auto"
SomeViewModel.kt
:
...
val propertyTypeFilter = MutableLiveData<MarsApiFilter>().apply { value = MarsApiFilter.ALL }
...
我想创建 ChipGroup 2 路绑定适配器。我已经复制了默认的 RadioGroup 绑定适配器并进行了一些更改,但它不适用于这两种方式。在以编程方式将数据设置为可观察的情况下,ChipGroup 从中检索更改。但手动 Chip selection 不会将更改设置为 observable。
这是我的适配器
@InverseBindingMethods(InverseBindingMethod(type = ChipGroup::class, attribute = "android:checkedButton", method = "getCheckedRadioButtonId"))
class ChipGroupBindingAdapter {
companion object {
@JvmStatic
@BindingAdapter("android:checkedButton")
fun setCheckedChip(view: ChipGroup?, id: Int) {
if (id != view?.checkedChipId) {
view?.check(id)
}
}
@JvmStatic
@BindingAdapter(value = ["android:onCheckedChanged", "android:checkedButtonAttrChanged"], requireAll = false)
fun setChipsListeners(view: ChipGroup?, listener: ChipGroup.OnCheckedChangeListener?,
attrChange: InverseBindingListener?) {
if (attrChange == null) {
view?.setOnCheckedChangeListener(listener)
} else {
view?.setOnCheckedChangeListener { group, checkedId ->
listener?.onCheckedChanged(group, checkedId)
attrChange.onChange()
}
}
}
}
}
布局文件:
<android.support.design.chip.ChipGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkedButton="@{viewModel.checkedBtnObs}"
app:singleSelection="true">
<android.support.design.chip.Chip
android:id="@+id/first_chip"
style="@style/Widget.MaterialComponents.Chip.Choice"
android:layout_width="110dp"
android:layout_height="wrap_content"
android:checkable="true"
android:text="@string/month_12"
app:chipBackgroundColor="@drawable/chip_background_selector" />
<android.support.design.chip.Chip
android:id="@+id/second_chip"
style="@style/Widget.MaterialComponents.Chip.Choice"
android:layout_width="110dp"
android:layout_height="wrap_content"
android:checkable="true"
android:text="@string/month_6"
android:textAlignment="center"
app:chipBackgroundColor="@drawable/chip_background_selector" />
<android.support.design.chip.Chip
android:id="@+id/third_chip"
style="@style/Widget.MaterialComponents.Chip.Choice"
android:layout_width="110dp"
android:layout_height="wrap_content"
android:checkable="true"
android:text="@string/month_1"
app:chipBackgroundColor="@drawable/chip_background_selector" />
</android.support.design.chip.ChipGroup>
并且可观察到:
val checkedBtnObs = ObservableInt(R.id.second_chip)
终于,我找到了解决办法。
InverseBindingMethod 方法应该是 getCheckedChipId
而不是 getCheckedRadioButtonId
此外,@=
应该像这样添加到 xml android:checkedButton="@{viewModel.checkedBtnObs}"
android:checkedButton="@={viewModel.checkedBtnObs}"
现在此适配器可用于 ChipGroup 2 向绑定
@InverseBindingMethods(InverseBindingMethod(type = ChipGroup::class, attribute = "android:checkedButton", method = "getCheckedChipId"))
class ChipGroupBindingAdapter {
companion object {
@JvmStatic
@BindingAdapter("android:checkedButton")
fun setCheckedChip(view: ChipGroup?, id: Int) {
if (id != view?.checkedChipId) {
view?.check(id)
}
}
@JvmStatic
@BindingAdapter(value = ["android:onCheckedChanged", "android:checkedButtonAttrChanged"], requireAll = false)
fun setChipsListeners(view: ChipGroup?, listener: ChipGroup.OnCheckedChangeListener?,
attrChange: InverseBindingListener?) {
if (attrChange == null) {
view?.setOnCheckedChangeListener(listener)
} else {
view?.setOnCheckedChangeListener { group, checkedId ->
listener?.onCheckedChanged(group, checkedId)
attrChange.onChange()
}
}
}
}
}
if (attrChange == null) {
view?.setOnCheckedChangeListener(listener)
} else {
view?.setOnCheckedChangeListener { group, checkedId ->
listener?.onCheckedChanged(group, checkedId)
attrChange.onChange()
}
}
}
也许应该
if (listener != null) {
view?.setOnCheckedChangeListener(listener)
} else {
view?.setOnCheckedChangeListener { group, checkedId ->
listener?.onCheckedChanged(group, checkedId)
attrChange.onChange()
}
}
}
我得到了 ChipGroup
,DataBinding
按预期工作并使用 InverseDataBinding
的推荐方式,如果有人想知道,这是我的实现:
SomeBindingAdapters.kt
:
...
object PropertyTypeFilterBindingAdapters {
@BindingAdapter("propertyTypeFilter")
@JvmStatic
fun ChipGroup.bindPropertyTypeFilter(marsApiFilter: MarsApiFilter?) =
marsApiFilter?.let { filter ->
when (filter) {
MarsApiFilter.ALL -> check(R.id.filter_all_properties_chip)
MarsApiFilter.RENT -> check(R.id.filter_properties_for_rent_chip)
MarsApiFilter.BUY -> check(R.id.filter_properties_for_buy_chip)
}
}
@InverseBindingAdapter(attribute = "propertyTypeFilter")
@JvmStatic
fun ChipGroup.convertToMarsApiFilter(): MarsApiFilter = when (checkedChipId) {
R.id.filter_properties_for_rent_chip -> MarsApiFilter.RENT
R.id.filter_properties_for_buy_chip -> MarsApiFilter.BUY
else -> MarsApiFilter.ALL
}
@BindingAdapter("propertyTypeFilterAttrChanged")
@JvmStatic
fun ChipGroup.setListeners(attrChange: InverseBindingListener?) =
setOnCheckedChangeListener { _, _ -> attrChange?.onChange() }
}
...
MarsApiFilter
是针对我的具体情况的枚举 class。
some_layout.xml
:
...
<com.google.android.material.chip.ChipGroup
android:id="@+id/filter_property_type_chip_group"
...
bind:propertyTypeFilter="@={viewModel.propertyTypeFilter}"
>
<com.google.android.material.chip.Chip
android:id="@+id/filter_all_properties_chip"
...
/>
<com.google.android.material.chip.Chip
android:id="@+id/filter_properties_for_rent_chip"
...
/>
<com.google.android.material.chip.Chip
android:id="@+id/filter_properties_for_buy_chip"
...
/>
</com.google.android.material.chip.ChipGroup>
...
bind
只是一个声明为常规名称空间的奇特名称空间:xmlns:bind="http://schemas.android.com/apk/res-auto"
SomeViewModel.kt
:
...
val propertyTypeFilter = MutableLiveData<MarsApiFilter>().apply { value = MarsApiFilter.ALL }
...