42

I am loading a list of categories and depending on which is selected, I need to show the products of the corresponding category in the RecyclerView. So when I first start the Fragment I need to simulate the user clicking in a default category - in this case, it would be the first one.

How can I perform this?

CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
noloman
  • 11,411
  • 20
  • 82
  • 129

7 Answers7

49

Without your code we don't know how you implement your onClickListener.

Normally, you implement and set the item onClickListener in the viewHolder of your RecyclerView.Adapter.
For example: ViewHolder.itemView.setOnClickListener(listener);

So the solution is you can use recyclerView.findViewHolderForAdapterPosition(0).itemView.performClick()

PS: Do not use findViewHolderForLayoutPosition() according to the Doc

Xiaoyi LI
  • 525
  • 3
  • 4
31

Here is a workaround to select 1st child of RecyclerView after just setting adapter.

//position to be clicked
final int pos = 0;
new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
recyclerView.findViewHolderForAdapterPosition(pos).itemView.performClick();
                    }
                },1);
CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
Saurabh
  • 449
  • 4
  • 9
  • 1
    Why do you suggest to use handler here? – Gaket Dec 03 '16 at 20:22
  • 3
    To delay 1 ms on click event because it was giving a null pointer exception sometimes. – Saurabh Dec 05 '16 at 08:19
  • 8
    Keep in mind you always can use `ViewTreeObserver.OnPreDrawListener` to avoid NPE and unreliable timeouts. Like this: `recyclerView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { recyclerView.findViewHolderForAdapterPosition(lastPosition).itemView.performClick(); recyclerView.getViewTreeObserver().removeOnPreDrawListener(this); return true; } });` – demaksee Aug 18 '17 at 10:44
  • 5
    it's better to use recyclerView.post() because it will run after the recyvlerView is calculated – daniel.keresztes Jun 30 '19 at 09:28
  • @KERiii it's better to use your option – varunkr Dec 16 '19 at 06:57
  • One should use this approach with caution. If you have more items than recyclerview can show on the screen then viewHolder for those invisible items will return as null. – Hitesh Bisht Jan 11 '20 at 06:27
15

It is frowned upon by purists to use the method

    recyclerView.findViewHolderForAdapterPosition(pos).itemView.performClick();

as it states in docs:

Return the ViewHolder for the item in the given position of the data set. Unlike {@link #findViewHolderForLayoutPosition(int)} this method takes into account any pending adapter changes that may not be reflected to the layout yet. On the other hand, if {@link Adapter#notifyDataSetChanged()} has been called but the new layout has not been calculated yet, this method will return null since the new positions of views are unknown until the layout is calculated. for exactly the reason that delaying with a thread is sometimes useful. Any call to notifyDataSetChanged() causes it to return null. Better to use the adapter method onBindViewHolder and check for position 0. Adjust for how you have set up your listener, the usual way is example here, created in ViewHolder constructor. Use an init variable to prevent it from being called again:

    @Override
    public void onBindViewHolder(FooAdapter.ViewHolder viewHolder, int position) {
     //code
     ...
     //do this last especially if you are using an animator

     if(position == 0 && isInit) {
        listener.onItemClick( viewHolder.itemView,0);
        isInit =false;

     }
  }
CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
Droid Teahouse
  • 893
  • 8
  • 15
7

if you want to click a particular view inside a row at position then use

recyclerView.findViewHolderForAdapterPosition(pos).itemView.findViewById(R.id.view_id).performClick();
ked
  • 2,426
  • 21
  • 24
1

The below code snipped do it for you and also avoids NullPointerException:

recyclerView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
    @Override
    public boolean onPreDraw() {
        recyclerView.findViewHolderForAdapterPosition(mPosition).itemView.performClick();
        recyclerView.getViewTreeObserver().removeOnPreDrawListener(this);
        return true;
    }
});
Alireza Noorali
  • 3,129
  • 2
  • 33
  • 80
1

In case someone is looking to just move the focus to a particular list item, they can call following method after RECYCLER VIEW HAS BEEN INITIALISED:

recyclerView.findViewHolderForAdapterPosition(index).itemView.requestFocus()

If View has not been initialized; normally it takes a while after you set the adapter to recycler view, then you can use postDelayed() method of Handler to run the above code after approx 1 second so that you give time for the view to be initialized properly.

Tarun Deep Attri
  • 8,174
  • 8
  • 41
  • 56
  • 1
    This worked for me when inserting a new item into the middle of a RecyclerView list and then forcing the newly inserted item to be the selected one, but I was able to use post() instead of postDelayed() since that allowed adequate time for the new item to be rendered. Since I didn't want to actually click the new item none of the other suggestions here solved my use case. – PhoenixRevealed Oct 27 '22 at 02:01
0

If you're already extending ListAdapter from androidx.recyclerview.widget.ListAdapter,

You can simply override:

override fun onCurrentListChanged(previousList: MutableList<DayMonth>, currentList: MutableList<DayMonth>) {
        super.onCurrentListChanged(previousList, currentList)
        this.presenter.onItemClickListener(currentList.size.minus(1))
        /**
          Last postion   : size.minus(1)
          First position : 0
        */
    }

as your Presenter would look like:

interface Presenter {
        fun onItemClickListener(position : Int)
}
Yasser AKBBACH
  • 539
  • 5
  • 7