【问题标题】:How to use the same RecyclerView adapter with Activity and Fragment in Kotlin?如何在 Kotlin 中使用与 Activity 和 Fragment 相同的 RecyclerView 适配器?
【发布时间】:2021-12-26 06:04:13
【问题描述】:

我创建了一个完美运行的应用程序。我决定对我的应用程序进行一些更改,即在某些地方使用Fragment 而不是Activity。此活动中有一个RecyclerView,用于加载从Firestore 获取的数据。除了使用Fragment 代替Activity 之外,一切都将保持不变。

现在我遇到的问题是 recyclerView 适配器,它需要上下文。

open class CargoListAdapter(
    private val context: Context,
    private var list: ArrayList<Cargo>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

单击按钮时,我必须检查上下文以采取相应的进一步操作。

            holder.binding.ibDelete.setOnClickListener {

            when (context) {
                is OrderActivity -> {
                    val activity = holder.itemView.context as? OrderActivity

                    activity?.viewSpecialRequest(
                        model.custom_request
                    )
                }

                is MyOrderDetailsActivity -> {
                    val activity = holder.itemView.context as? MyOrderDetailsActivity

                    activity?.viewSpecialRequest(
                        model.custom_request
                    )
                }

                is CargoFragment -> {
                    val activity = holder.itemView.context as? CargoFragment

                    activity?.editDeleteSpecialRequestDialog(
                        holder.binding.ibEditDeleteNote,
                        holder.binding.ibAddNote,
                        model.id,
                        model.custom_request
                    )

                }
            }
        }

这就是我从其中一项活动中调用的方式。

val cargoListAdapter = CargoListAdapter(this@OrderActivity, mCargoList)

我尝试从fragment 拨打电话,如下所示,但我在is CargoFragment -&gt; { 看到错误“不兼容的类型:CargoFragment 和上下文”

val cargoListAdapter = CargoListAdapter(requireContext(), mCargoList)

编辑: 这不是问题的一部分,而是显示当recyclerView 中有几个按钮时我做了什么,并根据单击的按钮采取行动。有人已经在接受的答案的评论框中询问过它。

现在适配器类的onClickItem 已根据我的要求进行更改。如您所见,我在哪里有action:String,它将让我知道单击了哪个按钮以及需要进一步执行哪些功能/操作。

open class CargoListAdapter(
    private val context: Context,
    private var list: ArrayList<Cargo>,
    private val onClickItem: (pos: Int,addButton: ImageButton,deleteButton: ImageButton,model: Cargo,action:String) -> Unit
) : RecyclerView.Adapter<RecyclerView.ViewHolder>()

onBindViewHolder我有以下内容。

 holder.binding.ibRemoveItem.setOnClickListener {
                        onClickItem(holder.adapterPosition,
                            holder.binding.ibAddNote,
                            holder.binding.ibDeleteNote,
                            model,
                            "removeItem")
}

每当单击一个按钮时,一个按钮onClickListener 的设置如上所述,并且根据按钮我更改“操作”的值。如您所见,在上面的示例中,它是“removeItem”,因此从下面的代码中将发生“removeItem”下的操作。 以下是我在“CargoFragment”中的内容

when (action) {
"DeleteNote" -> {
 ///TAKE SOME ACTION HERE
}
"AddNote" -> {
///TAKE SOME ACTION HERE
 }
"removeItem" -> {
///TAKE SOME ACTION HERE
}

这就是我为处理recyclerView 中有多个按钮的情况所做的工作,并且它可以正常工作。希望高手给点意见,让初学者知道这是否可以遵循。

【问题讨论】:

  • 我认为您需要将requireContext() 替换为this@CargoFragment,因为该片段不是上下文,因此context is CargoFragment -&gt; 会出现类型不匹配
  • 您为什么不尝试类似于我在this 回答您的问题时提出的建议?将回调 lambda 传递给您的适配器,并让调用者决定调用该 lambda 时要做什么。
  • 正如我在那里所说的,这对我作为初学者来说是新事物。我按照您的建议更改了几个类似的功能。但是,这是完全不同的东西,一个适配器,我不想破坏我所有的代码,试图自己实现你的版本。顺便说一句,我喜欢你的代码,我会尽可能为所有新代码使用相同的版本。
  • @Zain 为此,我必须将适配器类的参数“context”更改为CargoFragment。我不能这样做,因为活动也使用相同的适配器。

标签: android kotlin android-fragments android-recyclerview


【解决方案1】:

您可以使用 Kotlin 高阶函数来使适配器独立并在代码中的任何位置使用,而不是使用接口并通过使用 Activity 或 Fragment 实例来访问函数。

open class CargoListAdapter(
    private val context: Context,
    private var list: ArrayList<Cargo>,
    private val onClickItem:(pos: Int, viewId: Int) -> Unit
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

点击时在 ViewHolder 中调用 onClickItem :

    holder.binding.ibDelete.setOnClickListener {
        onClickItem(adapterPosition, it.id)
    }

    holder.binding.ibEdit.setOnClickListener {
        onClickItem(adapterPosition, it.id)
    }

在 Activity 或 Fragment 中:

adapter = CargoListAdapter(context, list){position, viewId->
   //receive click here
    when(viewId){
        R.id.ibDelete -> //Delete Action
        R.id.ibEdit -> //Delete Action
        // You can use sam click listener for multiple views by passing id
    }
}

查看此要点以获取完整的适配器示例:https://github.com/Noddy20/Gists/blob/master/RecyclerViewAdapter-1.kt

【讨论】:

  • 如果我需要单击另外三个按钮,例如不只是删除按钮,我该怎么做?写三个 kotlin 函数?
  • @Yura 请在我的问题中的“编辑”之后查找详细信息。希望这会有所帮助。
  • 就像我传递了 pos: Int for item position 一样,您也可以为单击的视图 id 传递另一个参数。比在 Activity/Fragment 中使用该视图 ID(带有条件 when/if/else)来执行您需要的操作。
  • @Yura 更新了多次查看点击的答案。
【解决方案2】:

您检查上下文,然后将其转换为创建适配器的活动或片段,然后在调用活动/片段方法viewSpecialRequest 这不是很正确,如果您想在单击后调用活动/片段方法ibDelete 你需要添加例如一个接口。

open class CargoListAdapter(
    private val context: Context,
    private var list: ArrayList<Cargo>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

interface OnItemActionsListener {
        fun onDeleteClicked()
    }

var onItemActionsListener:OnItemActionsListener? =null

 holder.binding.ibDelete.setOnClickListener {
     onItemActionsListener?.onDeleteClicked()
 } 

********* 
 }
}

订单活动

adapter = CargoListAdapter(this, arrayListOf())
adapter.onItemActionsListener = object  : CargoListAdapter.OnItemActionsListener {
                    override fun onDeleteClicked() {
                        // TODO logic
                    }
                }

货物片段

adapter = CargoListAdapter(requireActivity(), arrayListOf())
adapter.onItemActionsListener = object  : CargoListAdapter.OnItemActionsListener {
                    override fun onDeleteClicked() {
                        // TODO logic
                    }
                }

如果你需要在适配器中做逻辑,而不是上下文检查,你可以使用枚举。

public enum DeleteCaseEnum {
    NONE, CASE_1, CASE_2, CASE_3
}

open class CargoListAdapter(
    private val context: Context,
    private var list: ArrayList<Cargo>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

var deleteCase:DeleteCaseEnum  = DeleteCaseEnum .NONE

   holder.binding.ibDelete.setOnClickListener {

            when (deleteCase) {
                is DeleteCaseEnum.CASE_1-> {
                 // TODO
                }
              
                is DeleteCaseEnum.CASE_2-> {
                 // TODO
                }
            }

订单活动

adapter = CargoListAdapter(this, arrayListOf())
adapter.deleteCase = DeleteCaseEnum.CASE_1

货物片段

adapter = CargoListAdapter(requireActivity(), arrayListOf())
adapter.deleteCase = DeleteCaseEnum.CASE_2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多