[英]How to handle click in a nested RecyclerView
有人可以解释如何处理这个问题的逻辑:
我有一个片段,在 WebSocket 调用后膨胀了 2 个 Recyclerviews。
Child Recyclerview 嵌套在 Parent Recyclerview 中,父适配器调用子适配器。 我想为单击侦听器放置一个接口,该接口处理片段中子项中的单击。
我应该把接口放在哪里,哪个 class 应该实现它?
您尝试做的事情已经多次完成。
您可以尝试多种方法,但总的来说,职责如下所示:
YourContext
(片段/活动)RecyclerView
扩展布局。YourAdapter
YourAdapter
。interface YourThingClickHandler {
fun onThingWasClicked(thing: Thing) // and any other thing you may need.
}
YourContext: YourThingClickHandler
或者如果你愿意,你可以保留一个匿名/本地实例。 我通常做前者,然后在片段/活动中实现fun onThingWasClicked(...)
,这取决于单击项目时您需要做什么。YourAdapter
Things
列表和一个YourThingClickHandler
实例。 所以在你的片段/活动中你会做的事情,比如(伪代码):// This is called once your ViewModel/Presenter/Repository/etc. makes the data available.
fun onThingsLoaded(things: List<Thing>) {
adapter.setClickHandler(this) // this can be passed when you construct your adapter too via constructor like adapter = YourAdapter(this)
adapter.submitList(things) // if the adapter extends a `ListAdapter` this is all you need.
}
现在您已经传递了一个外部点击处理程序,您需要处理内部列表。 现在你有几个选择: 1. 一直传入相同的点击处理程序,让innerAdapter
直接与 this 对话。 2.让outerAdapter
充当innerAdapter中发生的点击之间的中间人,并通过您刚刚提供的这个点击处理程序将它们冒泡。
你选择哪一个,很大程度上取决于你想用它做什么,以及你想如何处理它。 在我看来没有对错之分。
不管你做什么,你仍然需要从视图持有者到这个点击处理程序......
所以在YourAdapter
你应该有另一个接口:
interface InternalClickDelegate {
fun onItemTappedAt(position: Int)
}
这个内部处理程序将用于从 viewHolder 与您的适配器对话,并将点击冒泡到外部单击处理程序。
现在你可以有一个这样的实例,在你的适配器 class 中定义(记住这是伪代码):
private val internalClickHandler: InternalClickDelegate? = object : InternalClickDelegate {
override fun onItemTappedAt(position: Int) {
externalClickHandler?.run {
onThingWasClicked(getItem(position))
}
}
}
因此,如果外部点击处理程序(您提供的YourThingClickHandler
)不是 null,则从适配器的数据源获取项目,并将其传递。
当你做onCreateViewHolder
时,有一个 ViewHolder 需要......你猜对了,一个InternalClickDelegate
实例等等......
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
// decide which viewHolder you're inflating... and...
return YourViewHolder(whateverViewYouInflate, internalClickHandler)
现在你的 ViewHolder(s) 有一个对这个内部点击处理程序的引用......
因此,当您执行onBindViewHolder(...)
时,您可能会调用您选择的通用 ViewHolder 方法,例如,如果您的 View Holder 可以是不同类型,您可能有一个带有fun bind(thing: Thing)
方法的 Abstract viewHolder 或类似于每个具体的 viewHolder 子类型都必须实现......在那里,你会做这样的事情:
override fun bind(thing: Thing) {
if (clickHandler != null) {
someViewYourViewHolderInflated.setOnClickListener(this) // this assumes your ViewHolder implements View.OnClickListener from the framework
}
}
因为您的 ViewHolder 实现了View.OnClickListener
,所以您必须在其中实现 onClick 方法:
override fun onClick(v: View?) {
clickHandler?.onItemTappedAt(adapterPosition)
}
这就是您的 ViewHolder 将如何在onClick
方法中接收来自 Android 的点击/点击事件,如果您提供了一个点击处理程序(您在传递 internalClickHandler 时在适配器 onCreateViewHolder 中做了),它只会冒泡点击,传递position。 adapterPosition
是 Kotlin 等效于在 RecyclerView 适配器中调用getAdapterPosition()
。
itemView
或您想要使其可点击的任何小部件,如果您希望整个单元格可点击,只需使用itemView
即可,它是 ViewHolder 的“整体”视图. 当viewHolder的view被点击时,android调用点击监听的onClick
方法。 在那里,因为您在 ViewHolder 中,您可以执行 getAdapterPosition() 并将其传递给您收到的internal
点击处理程序。
然后适配器可以将该 position 转换回数据,并且由于您提供了外部clickListener
,它可以将实际项目传递回外部点击侦听器。
没有什么特别的,你只需要提供相同的机制,并不断传递东西。 你做什么或者你有多少这些接口,完全取决于你想要实现什么; 就像我在开始时所说的那样,每个解决方案都是不同的,在做出架构决策时必须考虑其他因素。
一般来说,请记住这一点:关注点分离:保持小事和重点。 例如:拥有这个双重界面可能看起来很疯狂,但很清楚每个界面的作用。 内部的,只是关心“视图”中的“点击”,并在发生所述点击的列表中提供 position。
这是适配器需要获取数据并对真正被点击的项目做出明智猜测的“全部”。
片段不知道(或关心)“位置”,这是适配器的实现细节; positions
存在的事实对 Fragment 是无视的; 但是 Fragment 很高兴,因为它在回调中接收到Thing
,这是最有可能需要知道的(如果您出于任何原因需要了解 position,请定制和修改externalCallback
以具有您选择的签名。
现在将 OuterAdapter 中的“传递手”复制到 InnerAdapter,您已经完成了您想做的事情。
祝你好运!
1)您应该将接口放在子适配器中并在父适配器中实现,然后传递另一个接口(长时间)
2)使用本地广播管理器
您将在父适配器中添加 ClickListener 并将其添加到适配器的构造函数中
public interface HandleClickListener
{
void onItemClicked(int position, SurveysListModel surveysListModel);
}
创建一个 clicklistener 实例,然后在 holderclick listner 上从 model 列表中获取项目的 position 及其值
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handleClickListener.onItemClicked(position, yourModelList.get(position));
});
并像这样进入您的活动,制作您的适配器实例
adapter = new InstrumentsSearchAdapter(yourModelsList, activity.this, new SearchAdapter.HandleClickListener() {
@Override
public void onItemClicked(int position, Model listModel) {
instumentChild = listModel.getInstrument_title();
Intent intent = new Intent(Activity.this, Listing.class);
intent.putExtra("selectedQuestions", listModel.getQuestions());
startActivityForResult(intent, 5);
}
});
如果你想 go 到父 recyclerview class 实现 onActivityResutlt 方法并通过意图从孩子那里取回数据并在 onActivityResutlt 方法中获取该意图
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.