kotlin recyclerView项中的数据绑定不适用于fragment viewModel

nnsrf1az  于 2022-12-13  发布在  Kotlin
关注(0)|答案(1)|浏览(164)

我有一个recyclerView,它显示了购物车项目列表,每个项目都是可点击的,并打开了该项目的详细信息片段,我正在更新项目布局,使其内部有一个删除按钮,删除按钮应该调用片段viewModel中的一个方法。我认为在适配器中将viewModel作为一个构造函数并不是最佳实践,因为在我发展技能的过程中,关注点的分离很重要。
我正在用dataBinding做这件事,我已经搜索了很多,但没有找到答案。

购物车列表项目.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="makeupItem"
        type="com.melfouly.makeupshop.model.MakeupItem" />

    <variable
        name="viewModel"
        type="com.melfouly.makeupshop.makeupcart.CartViewModel" />

</data>

<com.google.android.material.card.MaterialCardView
    android:id="@+id/cart_card_item"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:layout_margin="4dp"
    android:backgroundTint="@color/primary"
    app:cardCornerRadius="8dp"
    app:cardElevation="8dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:weightSum="6">

        <ImageView
            android:id="@+id/item_image"
            loadImage="@{makeupItem}"
            android:layout_gravity="center"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:scaleType="fitCenter"
            tools:src="@tools:sample/avatars" />

        <TextView
            android:id="@+id/item_name"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2"
            android:fontFamily="@font/aclonica"
            android:gravity="center"
            android:text="@{makeupItem.name}"
            android:textColor="@color/black"
            android:textStyle="bold"
            tools:text="Item name" />

        <TextView
            android:id="@+id/item_price"
            loadPrice="@{makeupItem}"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2"
            android:fontFamily="@font/aclonica"
            android:gravity="center"
            android:textColor="@color/black"
            tools:text="5$" />

        <Button
            android:id="@+id/delete_button"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:onClick="@{() -> viewModel.deleteItemFromCart(makeupItem)}"
            app:icon="@drawable/ic_baseline_delete_outline_24"
            app:iconGravity="end" />

    </LinearLayout>

</com.google.android.material.card.MaterialCardView>
</layout>

推车适配器

class CartAdapter(private val clickListener: (MakeupItem) -> Unit) :
ListAdapter<MakeupItem, CartAdapter.CartViewHolder>(DiffCallback()) {

class CartViewHolder(private val binding: CartListItemBinding) :
    RecyclerView.ViewHolder(binding.root) {
    fun bind(makeupItem: MakeupItem) {
        binding.makeupItem = makeupItem
        binding.executePendingBindings()
    }
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CartViewHolder {
    val layoutInflater = LayoutInflater.from(parent.context)
    val binding = CartListItemBinding.inflate(layoutInflater, parent, false)
    return CartViewHolder(binding)
}

override fun onBindViewHolder(holder: CartViewHolder, position: Int) {
    val makeupItem = getItem(position)
    holder.itemView.setOnClickListener {
        clickListener(makeupItem)
    }
    holder.bind(makeupItem)
}

class DiffCallback : DiffUtil.ItemCallback<MakeupItem>() {
    override fun areItemsTheSame(oldItem: MakeupItem, newItem: MakeupItem): Boolean {
        return oldItem.id == newItem.id
    }

    override fun areContentsTheSame(oldItem: MakeupItem, newItem: MakeupItem): Boolean {
        return oldItem == newItem
    }
}

CartViewModel删除函数

fun deleteItemFromCart(makeupItem: MakeupItem) {
    viewModelScope.launch {
        Log.d(TAG, "DeleteItemFromCart method in viewModel called")
        repository.deleteItemFromCart(makeupItem)
    }
}
olhwl3o2

olhwl3o21#

我有答案了。
viewModel与recyclerView项的DataBinding将不起作用,因为我们没有在此viewModel中声明适配器,因此您应该在适配器中进行回调,并在片段中接收它,然后调用viewModel函数。

以下是修改了单击上的删除按钮的回调后的CartAdapter,并对cardItem使用相同的方法

class CartAdapter(
private val cartItemClickListener: CartItemClickListener,
private val deleteItemClickListener: DeleteItemClickListener
) :
ListAdapter<MakeupItem, CartAdapter.CartViewHolder>(DiffCallback()) {

class CartViewHolder(private val binding: CartListItemBinding) :
    RecyclerView.ViewHolder(binding.root) {
    fun bind(
        makeupItem: MakeupItem,
        cartItemClickListener: CartItemClickListener,
        deleteItemClickListener: DeleteItemClickListener
    ) {
        binding.makeupItem = makeupItem
        binding.cartItemClickListener = cartItemClickListener
        binding.deleteItemClickListener = deleteItemClickListener
        binding.executePendingBindings()
    }
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CartViewHolder {
    val layoutInflater = LayoutInflater.from(parent.context)
    val binding = CartListItemBinding.inflate(layoutInflater, parent, false)
    return CartViewHolder(binding)
}

override fun onBindViewHolder(holder: CartViewHolder, position: Int) {
    val makeupItem = getItem(position)
    holder.bind(makeupItem, cartItemClickListener, deleteItemClickListener)
}

class DiffCallback : DiffUtil.ItemCallback<MakeupItem>() {
    override fun areItemsTheSame(oldItem: MakeupItem, newItem: MakeupItem): Boolean {
        return oldItem.id == newItem.id
    }

    override fun areContentsTheSame(oldItem: MakeupItem, newItem: MakeupItem): Boolean {
        return oldItem == newItem
    }
}

class CartItemClickListener(val clickListener: (makeupItem: MakeupItem) -> Unit) {
    fun onClick(makeupItem: MakeupItem) = clickListener(makeupItem)
}

class DeleteItemClickListener(val deleteItemClickListener: (makeupItem: MakeupItem) -> Unit) {
    fun onClick(makeupItem: MakeupItem) = deleteItemClickListener(makeupItem)
}

}

对于CartListItem,添加两个dataBinding,一个用于itemClickListener,另一个用于deleteButtonClickListener,并在其中使用android:onClick和lambda表达式

<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="makeupItem"
        type="com.melfouly.makeupshop.model.MakeupItem" />

    <variable
        name="cartItemClickListener"
        type="com.melfouly.makeupshop.makeupcart.CartAdapter.CartItemClickListener" />

    <variable
        name="deleteItemClickListener"
        type="com.melfouly.makeupshop.makeupcart.CartAdapter.DeleteItemClickListener" />

</data>

<com.google.android.material.card.MaterialCardView
    android:id="@+id/cart_card_item"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:layout_margin="4dp"
    android:backgroundTint="@color/primary"
    android:onClick="@{() -> cartItemClickListener.onClick(makeupItem)}"
    app:cardCornerRadius="8dp"
    app:cardElevation="8dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:weightSum="6">

        <ImageView
            android:id="@+id/item_image"
            loadImage="@{makeupItem}"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:scaleType="fitCenter"
            tools:src="@tools:sample/avatars" />

        <TextView
            android:id="@+id/item_name"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2"
            android:fontFamily="@font/aclonica"
            android:gravity="center"
            android:text="@{makeupItem.name}"
            android:textColor="@color/black"
            android:textStyle="bold"
            tools:text="Item name" />

        <TextView
            android:id="@+id/item_price"
            loadPrice="@{makeupItem}"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2"
            android:fontFamily="@font/aclonica"
            android:gravity="center"
            android:textColor="@color/black"
            tools:text="5$" />

        <Button
            android:id="@+id/delete_button"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:onClick="@{() -> deleteItemClickListener.onClick(makeupItem)}"
            app:icon="@drawable/ic_baseline_delete_outline_24"
            app:iconGravity="end" />

    </LinearLayout>

</com.google.android.material.card.MaterialCardView>
</layout>

到达片段并声明适配器后,传递适配器参数,这些参数将执行特定的viewModel函数或每次单击cardItem和delete按钮时需要实现的任何功能

adapter = CartAdapter(CartAdapter.CartItemClickListener { makeupItem ->
        viewModel.onMakeupItemClicked(makeupItem)
    }, CartAdapter.DeleteItemClickListener { makeupItem ->
        viewModel.deleteItemFromCart(makeupItem)
    }
    )

我希望这是最好的实践答案,并帮助每个人都有同样的问题。

相关问题