如何在 Kotlin 中使用与 Activity 和 Fragment 相同的 RecyclerView 适配器?
Posted
技术标签:
【中文标题】如何在 Kotlin 中使用与 Activity 和 Fragment 相同的 RecyclerView 适配器?【英文标题】:How to use the same RecyclerView adapter with Activity and Fragment in Kotlin? 【发布时间】: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 ->
看到错误“不兼容的类型: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 ->
会出现类型不匹配
您为什么不尝试类似于我在this 回答您的问题时提出的建议?将回调 lambda 传递给您的适配器,并让调用者决定调用该 lambda 时要做什么。
正如我在那里所说的,这对我作为初学者来说是新事物。我按照您的建议更改了几个类似的功能。但是,这是完全不同的东西,一个适配器,我不想破坏我所有的代码,试图自己实现你的版本。顺便说一句,我喜欢你的代码,我会尽可能为所有新代码使用相同的版本。
@Zain 为此,我必须将适配器类的参数“context”更改为CargoFragment
。我不能这样做,因为活动也使用相同的适配器。
【参考方案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
【讨论】:
以上是关于如何在 Kotlin 中使用与 Activity 和 Fragment 相同的 RecyclerView 适配器?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Kotlin 中将数据从 Service 传递到 Activity?
如何通过单击 Image Kotlin Android 来移动 Activity
Kotlin 上的 Android:如何将数据从 Activity 传递到事件监听器?
Kotlin BaseNodeProvider()如何转跳到Activity