1)您应该将接口放在子适配器中,并在父适配器中实现,然后传递另一个接口(长进程)
2)使用本地广播管理器
有人可以解释如何处理此问题的逻辑:
我有一个片段,在WebSocket调用之后,该片段会使2个Recyclerviews膨胀。
Child Recyclerview嵌套到Parent Recyclerview,并且父适配器调用子适配器。我想为单击侦听器提供一个接口,以处理片段中“子项”中的单击。
我应该在哪里放置该接口,以及应该在哪个类中实现它?
您尝试做的事情已经完成了多次。
您可以尝试多种方法,但是总的来说,责任看起来像这样:
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
直接与其交谈。2.让outerAdapter
充当innerAdapter中发生的单击之间的中介,并通过您刚刚提供的此单击处理程序使它们起泡。
您选择的是哪个,很大程度上取决于您要使用它的方式以及处理方式。我认为没有对与错。
无论您做什么,都仍然需要从视图持有者]进入此点击处理程序...
因此,在YourAdapter
中,您应该具有另一个接口:
interface InternalClickDelegate { fun onItemTappedAt(position: Int) }
此内部处理程序将用于从viewHolder进行交谈,返回到您的适配器,并将水龙头冒泡到外部单击处理程序。
现在您可以拥有一个实例,在您的适配器类中这样定义(请记住这是伪代码):
private val internalClickHandler: InternalClickDelegate? = object : InternalClickDelegate { override fun onItemTappedAt(position: Int) { externalClickHandler?.run { onThingWasClicked(getItem(position)) } } }
因此if
外部单击处理程序(您提供的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具有对该内部点击处理程序的引用...
因此,当您执行
onBindViewHolder(...)
时,您可能会调用您选择的通用ViewHolder方法,例如,如果您的View Holder可以是不同类型,则您可能有一个带有fun bind(thing: Thing)
方法的Abstract viewHolder或与每个具体viewHolder相似的类subType必须实现...在那里,您需要执行以下操作:
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接收点击/点击事件的方式,如果您提供了一个Click Handler(您在传递internalClickHandler时在onCreateViewHolder适配器中所做的操作),则会简单地冒泡点击,传递位置。adapterPosition
与在RecyclerView适配器中调用getAdapterPosition()
的Kotlin等效。太长,看不懂图
itemView
或只是您想要使其可单击的任何小部件,如果您希望整个单元格都可单击,则只需使用itemView
这是ViewHolder的“整个”视图。[当点击viewHolder的视图时,android会调用点击监听器的onClick
方法。在其中,并且因为您在ViewHolder中,所以可以执行getAdapterPosition()并将其传递给收到的internal
单击处理程序。
然后适配器可以将该位置转换回数据,并且由于您提供了外部clickListener
,因此它可以将实际项目传递回外部Click侦听器。
没什么特别的,您只需要提供相同的机制,并不断传递信息即可。您做什么或拥有多少这些接口完全取决于您要实现的目标。就像我刚开始所说的那样,每种解决方案都是不同的,并且在做出体系结构决策时必须考虑其他因素。
通常,请牢记这一点:关注点分离
:将事情保持较小,并且切入要点。例如:拥有这个双重界面似乎很疯狂,但很清楚每个界面的作用。内部的只是关注“视图”中的“点击”,并在所述点击发生的列表中提供位置。这是适配器需要的所有信息,以获取数据并就什么东西真正被窃听做出明智的猜测。
该片段不知道(也不关心)“位置”,这是Adapter的实现细节; positions
存在的事实忽略了该片段;但是Fragment很高兴,因为它在回调中接收到Thing
,这很可能是您需要知道的(如果您出于某种原因需要知道位置,请对externalCallback
进行裁剪和修改,使其具有您的签名)选择。
现在将“传递手”从您的OuterAdapter复制到您的InnerAdapter,并且您已经完成了想做的事情。
祝你好运!
1)您应该将接口放在子适配器中,并在父适配器中实现,然后传递另一个接口(长进程)
2)使用本地广播管理器
您将在父适配器中添加ClickListener并在适配器的构造函数中添加它
public interface HandleClickListener { void onItemClicked(int position, SurveysListModel surveysListModel); }
创建clicklistener的实例,然后在holderclick listner上,从模型列表中获取项目的位置及其值
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);
}
});
并且如果您想转到父级recyclerview类,请实现onActivityResutlt方法,并通过意图从子级取回数据,并在onActivityResutlt方法中获得该意图
1)您应该将接口放在子适配器中,并在父适配器中实现,然后传递另一个接口(长进程)
2)使用本地广播管理器
您将在父适配器中添加ClickListener并在适配器的构造函数中添加它
public interface HandleClickListener { void onItemClicked(int position, SurveysListModel surveysListModel); }
创建clicklistener的实例,然后在holderclick listner上,从模型列表中获取项目的位置及其值