如何处理嵌套的RecyclerView中的单击

问题描述 投票:0回答:3

有人可以解释如何处理此问题的逻辑:

我有一个片段,在WebSocket调用之后,该片段会使2个Recyclerviews膨胀。

Child Recyclerview嵌套到Parent Recyclerview,并且父适配器调用子适配器。我想为单击侦听器提供一个接口,以处理片段中“子项”中的单击。

我应该在哪里放置该接口,以及应该在哪个类中实现它?

android android-fragments android-recyclerview interface listener
3个回答
1
投票

您尝试做的事情已经完成了多次。

您可以尝试多种方法,但是总的来说,责任看起来像这样:

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等效。

太长,看不懂图

  • Fragment:ExternalClickListener->将其实例传递给适配器。
  • Adapter:接收ExternalClickListener,将InternalClickListener传递给每个ViewHolder。
  • ViewHolder:接收内部的Click Listener,将其自身设置为Clickable(整个itemView或只是您想要使其可单击的任何小部件,如果您希望整个单元格都可单击,则只需使用itemView这是ViewHolder的“整个”视图。
  • [当点击viewHolder的视图时,android会调用点击监听器的onClick方法。在其中,并且因为您在ViewHolder中,所以可以执行getAdapterPosition()并将其传递给收到的internal单击处理程序。

    然后适配器可以将该位置转换回数据,并且由于您提供了外部clickListener,因此它可以将实际项目传递回外部Click侦听器。

等等,但是使用NESTED RecyclerView怎么样。>>

没什么特别的,您只需要提供相同的机制,并不断传递信息即可。您做什么或拥有多少这些接口完全取决于您要实现的目标。就像我刚开始所说的那样,每种解决方案都是不同的,并且在做出体系结构决策时必须考虑其他因素。

通常,请牢记这一点:关注点分离

:将事情保持较小,并且切入要点。例如:拥有这个双重界面似乎很疯狂,但很清楚每个界面的作用。内部的只是关注“视图”中的“点击”,并在所述点击发生的列表中提供位置。

这是适配器需要的所有信息,以获取数据并就什么东西真正被窃听做出明智的猜测。

该片段不知道(也不关心)“位置”,这是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方法中获得该意图


0
投票

1)您应该将接口放在子适配器中,并在父适配器中实现,然后传递另一个接口(长进程)

2)使用本地广播管理器


0
投票

您将在父适配器中添加ClickListener并在适配器的构造函数中添加它

public interface HandleClickListener
 {
    void onItemClicked(int position, SurveysListModel surveysListModel);
   }

创建clicklistener的实例,然后在holderclick listner上,从模型列表中获取项目的位置及其值

© www.soinside.com 2019 - 2024. All rights reserved.