我有一个recyclerview.widget.ListAdapter可以在网格中显示一些卡片。当我单击卡时,它会出现在网格的前面,翻转,并且当您看到前面时,您应该会喜欢它。我在卡片正面的一角有一个ImageView,应该在喜欢与否之间切换,显示我已经定义的另一个可绘制对象。
我的ViewHolder看起来像这样:
class GameCardViewHolder(private val binding : ItemGameCardBinding) :
RecyclerView.ViewHolder(binding.root){
companion object {
fun from(parent: ViewGroup): GameCardViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = ItemGameCardBinding.inflate(layoutInflater, parent, false)
return GameCardViewHolder(binding)
}
...
}
fun bind(productCard: ProductCard, listener: OnClickListener){
binding.productCard = productCard
binding.executePendingBindings()
...
}
}
我的item_game_card.xml看起来像这样:
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="productCard"
type="company.app.model.ProductCard" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout>
...
<ImageView
android:id="@+id/gameItemLikeImageView"
android:layout_width="0dp"
android:layout_height="0dp"
...
app:imageDrawable="@{productCard.liked}"
android:onClick="@{() -> productCard.toggleLike()}"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
我的BindingAdapters.kt:
@BindingAdapter("imageDrawable")
fun bindImageDrawable(imgView: ImageView, boolean: LiveData<Boolean>?) {
Timber.d("Binding liked: $boolean")
when(boolean?.value){
true -> imgView.setImageResource(R.drawable.ic_card_like)
false -> imgView.setImageResource(R.drawable.ic_card_dislike)
}
}
还有我的ProductCard.kt:
data class ProductCard(
val position: Int,
val product: Product
){
...
private val _liked = MutableLiveData(false)
val liked : LiveData<Boolean>
get() = _liked
fun toggleLikeProduct(){
Timber.d("Toggle like before: ${_liked.value}")
val oldValue = _liked.value!!
_liked.value = !oldValue
Timber.d("Toggle like after: ${_liked.value}")
}
}
当我单击ImageView时,控制台每次都会正确打印出before和after值,因此我知道liked
LiveData的值实际上正在更改,但是View没有相应地更新,即因为绑定适配器仅被调用一次(我猜是在binding.executePendingBindings()
中,当RecyclerView绑定ViewHolder时,而不是每次LiveData更改时)。
我希望每次liked
LiveData更改时都运行BindingAdapter代码。
当我使用ViewModel和Fragment布局执行此操作时,每次LiveData在ViewModel中更改时,视图都会更改,因为xml引用了该LiveData,但我不知道为什么,涉及到ProductCard和recyclerview项目布局,即使xml引用的是LiveData,视图也不会更改,但xml实际上并未绑定到LiveData,这就是拥有LiveData的全部目的。
我已经以一种非常粗暴,毫不含糊的方式实现了这种行为,在该视图上设置了onClickListener,并强迫它更改了它在OnBindViewHolder上可绘制的资源:
fun bind(productCard: ProductCard, listener: OnClickListener){
binding.productCard = productCard
binding.executePendingBindings()
binding.gameItemLikeImageView.setOnClickListener {
it?.let {
val card = binding.productCard
Timber.d("Tried changing liked status: ${card!!.liked}")
val old = card.liked
card.liked = !old
binding.productCard = card
val card2 = binding.productCard
Timber.d("Tried changing liked status: ${card2!!.liked}")
if (!old){
it.setBackgroundResource(R.drawable.ic_card_like)
}
else {
it.setBackgroundResource(R.drawable.ic_card_dislike)
}
}
}
...
}
但是我真的希望每张卡的行为都由绑定到的ProductCard对象的状态来控制。
我还尝试过每次单击都强制打binding.executePendingBindings()
,但也没用。
如何制作item_game_card.xml来观察LiveData中的更改?
答案 0 :(得分:0)
app:imageDrawable
将不接受任何LiveData<Boolean>
,我想知道为什么它不是LiveData<Product>
?尝试像这样绑定初始值:
app:imageDrawable="@{product.liked ? R.drawable_liked : R.drawable_neutral}"
对于LiveData
,需要为绑定设置LifecycleOwner
:
class ProductsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Inflate view and obtain an instance of the binding class.
val binding: ProductsBinding = DataBindingUtil.setContentView(this, R.layout.products)
// Specify the current activity as the lifecycle owner.
binding.setLifecycleOwner(this)
}
}
请参见documentation。