Get clicked item and its position in RecyclerView

AndroidListviewAndroid Recyclerview

Android Problem Overview


I am replacing my ListView with RecyclerView, list showing ok, but I would like to know how to get clicked item and its position, similar to the method OnItemClickListener.onItemClick(AdapterView parent, View v, int position, long id) we use in ListView.

Thanks for ideas!

Android Solutions


Solution 1 - Android

Based on the link: Why doesn't RecyclerView have onItemClickListener()? and How RecyclerView is different from Listview?, and also @Duncan's general idea, I give my solution here:

  • Define one interface RecyclerViewClickListener for a passing message from the adapter to Activity/Fragment:

      public interface RecyclerViewClickListener {
          public void recyclerViewListClicked(View v, int position);
      }
    
  • In Activity/Fragment implement the interface, and also pass listener to adapter:

      @Override
      public void recyclerViewListClicked(View v, int position){... ...}
    
      //set up adapter and pass clicked listener this
      myAdapter = new MyRecyclerViewAdapter(context, this);
    
  • In Adapter and ViewHolder:

      public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ItemViewHolder> {
         ... ... 
         private Context context;
         private static RecyclerViewClickListener itemListener;
    
    
         public MyRecyclerViewAdapter(Context context, RecyclerViewClickListener itemListener) {
             this.context = context;
             this.itemListener = itemListener;
             ... ...
         }
    
    
         //ViewHolder class implement OnClickListener, 
         //set clicklistener to itemView and, 
         //send message back to Activity/Fragment 
         public static class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
             ... ...
             public ItemViewHolder(View convertView) {
                 super(convertView);
                 ... ...
                 convertView.setOnClickListener(this);
             }
    
             @Override
             public void onClick(View v) {
                 itemListener.recyclerViewListClicked(v, this.getPosition());		
    
             }
         }
      }
    

After testing, it works fine.

[UPDATE]

Since API 22, RecyclerView.ViewHolder.getPosition() is deprecated, so instead with getLayoutPosition().

Solution 2 - Android

public class MyRvAdapter extends RecyclerView.Adapter<MyRvAdapter.MyViewHolder>{
    public Context context;
    public ArrayList<RvDataItem> dataItems;
	
	...
	constructor
	overrides
	...
	
	class MyViewHolder extends RecyclerView.ViewHolder{
        public TextView textView;
        public Context context;

        public MyViewHolder(View itemView, Context context) {
            super(itemView);

            this.context = context;

            this.textView = (TextView)itemView.findViewById(R.id.textView);

            // on item click
            itemView.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View v) {
                    // get position
                    int pos = getAdapterPosition();

                    // check if item still exists
                    if(pos != RecyclerView.NO_POSITION){
                        RvDataItem clickedDataItem = dataItems.get(pos);
                        Toast.makeText(v.getContext(), "You clicked " + clickedDataItem.getName(), Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    }
}

Solution 3 - Android

Here is an Example to set a Click Listener.

Adapter extends  RecyclerView.Adapter<MessageAdapter.MessageViewHolder> {  ...  }

 public static class MessageViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public TextView 	tv_msg;
        public TextView 	tv_date;
        public TextView 	tv_sendTime;
        public ImageView    sharedFile;
        public ProgressBar sendingProgressBar;
    
        public MessageViewHolder(View v) {
            super(v);
            tv_msg =  (TextView) v.findViewById(R.id.tv_msg);
            tv_date = (TextView)  v.findViewById(R.id.tv_date);
            tv_sendTime = (TextView)  v.findViewById(R.id.tv_sendTime);
            sendingProgressBar = (ProgressBar) v.findViewById(R.id.sendingProgressBar);
            sharedFile = (ImageView) v.findViewById(R.id.sharedFile);
    
            sharedFile.setOnClickListener(this);
    
        }
    
        @Override
        public void onClick(View view) {
        int position  =   getAdapterPosition();
    
    
            switch (view.getId()){
                case R.id.sharedFile:
    
    
                    Log.w("", "Selected"+position);
    
    
                    break;
            }
        }
    
    }

Solution 4 - Android

Put this code where you define recycler view in activity.

    rv_list.addOnItemTouchListener(
            new RecyclerItemClickListener(activity, new RecyclerItemClickListener.OnItemClickListener() {
                @Override
                public void onItemClick(View v, int position) {

                    Toast.makeText(activity, "" + position, Toast.LENGTH_SHORT).show();
                }
            })
    );

Then make separate class and put this code:

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {

    private OnItemClickListener mListener;
    public interface OnItemClickListener {
        public void onItemClick(View view, int position);
    }
    GestureDetector mGestureDetector;
    public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
        mListener = listener;
        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return true;
            }
        });
    }
    @Override
    public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
        View childView = view.findChildViewUnder(e.getX(), e.getY());
        if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
            mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
        }
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }
}

Solution 5 - Android

create java file with below code

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
private OnItemClickListener mListener;

public interface OnItemClickListener {
    public void onItemClick(View view, int position);
}

GestureDetector mGestureDetector;

public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
    mListener = listener;
    mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
        @Override public boolean onSingleTapUp(MotionEvent e) {
            return true;
        }
    });
}

@Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
    View childView = view.findChildViewUnder(e.getX(), e.getY());
    if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
        mListener.onItemClick(childView, view.getChildLayoutPosition(childView));
        return true;
    }
    return false;
}

@Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { }

@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

}

and just use the listener on your RecyclerView object.

recyclerView.addOnItemTouchListener(  
new RecyclerItemClickListener(context, new RecyclerItemClickListener.OnItemClickListener() {
  @Override public void onItemClick(View view, int position) {
    // TODO Handle item click
  }
}));

Solution 6 - Android

If you want Click event of recycle-View from activity/fragment instead of adapter then you can also use following short cut way.

recyclerView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                final TextView txtStatusChange = (TextView)v.findViewById(R.id.txt_key_status);
                txtStatusChange.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Log.e(TAG, "hello text " + txtStatusChange.getText().toString() + " TAG " + txtStatusChange.getTag().toString());
                        Util.showToast(CampaignLiveActivity.this,"hello");
                    }
                });
                return false;
            }
        });

You can also use other long ways like using interface

Solution 7 - Android

recyclerViewObject.addOnItemTouchListener(
    new RecyclerItemClickListener(
        getContext(),
        recyclerViewObject,
        new RecyclerItemClickListener.OnItemClickListener() {
            @Override public void onItemClick(View view, int position) {
                // view is the clicked view (the one you wanted
                // position is its position in the adapter
            }
            @Override public void onLongItemClick(View view, int position) {
            }
        }
    )
);

Solution 8 - Android

Use below code:-

public class SergejAdapter extends RecyclerView.Adapter<SergejAdapter.MyViewHolder>{

...

class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{


    @Override
    public void onClick(View v) {
        // here you use position
        int position = getAdapterPosition();
        ...

    }
}
}

Solution 9 - Android

> Here is the simplest and the easiest way to find the position of the clicked item:

I've also faced the same problem.

I wanted to find of the position of the clicked/selected item of the RecyclerView() and perform some specific operations on that particular item.

getAdapterPosition() method works like a charm for these kind of stuff. I found this method after a day of long research and after trying numerous other methods.

int position = getAdapterPosition();
Toast.makeText(this, "Position is: "+position, Toast.LENGTH_SHORT).show();

You do not have to use any extra method. Just create a global variable named 'position' and initialize it with getAdapterPosition() in any of the major method of the adapter (class or similar).

Here is a brief documentation from this link.

> getAdapterPosition added in version 22.1.0 int getAdapterPosition () Returns the Adapter position of the item represented by this ViewHolder. Note that this might be different than the getLayoutPosition() if there are pending adapter updates but a new layout pass has not happened yet. RecyclerView does not handle any adapter updates until the next layout traversal. This may create temporary inconsistencies between what user sees on the screen and what adapter contents have. This inconsistency is not important since it will be less than 16ms but it might be a problem if you want to use ViewHolder position to access the adapter. Sometimes, you may need to get the exact adapter position to do some actions in response to user events. In that case, you should use this method which will calculate the Adapter position of the ViewHolder.

Happy to help. Feel free to ask doubts.

Solution 10 - Android

My simple solution

Make a position holder:

    public class PositionHolder {

    private int position;

    public PositionHolder(int position) {
        this.position = position;
    }

    public int getPosition() {
        return position;
    }

    public void setPosition(int position) {
        this.position = position;
    }
}

Just position or put data you need to get from activity.

Adapter constructor:

public ItemsAdapter(Context context, List<Item> items, PositionHolder positionHolder){
        this.context = context;
        this.items = items;
        this.positionHolder = positionHolder;
}

In Activity:

 @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        selectedPosition = 0;

        positionHolder = new PositionHolder(selectedPosition);
        initView();
    }

In Adapter onClickLictener in the item
in onBindViewHolder

holder.holderButton.setOnClickListener(v -> {
            positionHolder.setPosition(position);
            notifyDataSetChanged();
        });

Now whenever you change position in RecyclerView it is hold in the Holder (or maybe it should be called Listener)

I hope it will be usefull

My first post ;P

Solution 11 - Android

RecyclerView doesn't provide such method.

To manage click events on RecyclerView I ended up implementing onClickListener in my adapter, when binding the ViewHolder: In my ViewHolder I keep a reference to the root view (as you can do with your ImageViews, TextViews, etc...) and when binding the viewHolder I set a tag on it with information I need to handle click (such as position) and a clicklistener

Solution 12 - Android

Everytime I use another approach. People seem to store or get position on a view, rather than storing a reference to an object that is displayed by ViewHolder.

I use this approach instead, and just store it in ViewHolder when onBindViewHolder() is called, and set reference to null in onViewRecycled().

Every time ViewHolder becomes invisible, it's recycled. So this doesn't affect in large memory consumption.

@Override
public void onBindViewHolder(final ItemViewHolder holder, int position) {
    ...
    holder.displayedItem = adapterItemsList.get(i);
    ...
}

@Override
public void onViewRecycled(ItemViewHolder holder) {
    ...
    holder.displayedItem = null;
    ...
}

class ItemViewHolder extends RecyclerView.ViewHolder {
    ...
    MySuperItemObject displayedItem = null;
    ...
}

Solution 13 - Android

From the designer, you can set the onClick property of the listItem to a method defined with a single parameter. I have an example method defined below. The method getAdapterPosition will give you the index of the selected listItem.

public void exampleOnClickMethod(View view){
    myRecyclerView.getChildViewHolder(view).getAdapterPosition());
}

For information on setting up a RecyclerView, see the documentation here: https://developer.android.com/guide/topics/ui/layout/recyclerview

Solution 14 - Android

The simple (but not so obvious) solution is to do this:

@Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

        View v = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.recycler_row, viewGroup, false);
        ViewHolder vh = new ViewHolder(v);

and then, whenever, call the method currentPosition = vh.getLayoutPosition();

In my case, I do that in an onClick listener put on that vh View. IMHO, the recycleView class misses out in that .getPosition() and other features that we know from ListView, and that are sometimes mandatory, are simply not available. I strongly regret having moved from ListView to Recycle ditto. The timethief cost was more than a day to unveil its mysteries. Bad engineering. (But what is there is ok)

Solution 15 - Android

//Create below methods into the Activity which contains RecyclerView.
  

private void createRecyclerView() {

final RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    MyAdapter myAdapter=new MyAdapter(dataAray,MianActivity.this);
    recyclerView.setAdapter(myAdapter);
    recyclerView.setItemAnimator(new DefaultItemAnimator());

    setRecyclerViewClickListner(recyclerView);
}

private void setRecyclerViewClickListner(RecyclerView recyclerView){

    final GestureDetector gestureDetector = new GestureDetector(MainActivity.this,new GestureDetector.SimpleOnGestureListener() {
        @Override public boolean onSingleTapUp(MotionEvent e) {
            return true;
        }
    });


    recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
        @Override
        public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
            View child =recyclerView.findChildViewUnder(motionEvent.getX(),motionEvent.getY());
            if(child!=null && gestureDetector.onTouchEvent(motionEvent)){
               int position=recyclerView.getChildLayoutPosition(child);
                String name=itemArray.get(position).name;

            return true;
        }

        @Override
        public void onTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {

        }

        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean b) {

        }
    });
}

Solution 16 - Android

Try in this way

Adapter class :

 public class ContentAdapter extends RecyclerView.Adapter<ContentAdapter.ViewHolder> {

public interface OnItemClickListener {
    void onItemClick(ContentItem item);
}

private final List<ContentItem> items;
private final OnItemClickListener listener;

public ContentAdapter(List<ContentItem> items, OnItemClickListener listener) {
    this.items = items;
    this.listener = listener;
}

@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_item, parent, false);
    return new ViewHolder(v);
}

@Override public void onBindViewHolder(ViewHolder holder, int position) {
    holder.bind(items.get(position), listener);
}

@Override public int getItemCount() {
    return items.size();
}

static class ViewHolder extends RecyclerView.ViewHolder {

    private TextView name;
    private ImageView image;

    public ViewHolder(View itemView) {
        super(itemView);
        name = (TextView) itemView.findViewById(R.id.name);
        image = (ImageView) itemView.findViewById(R.id.image);
    }

    public void bind(final ContentItem item, final OnItemClickListener listener) {
        name.setText(item.name);
        itemView.setOnClickListener(new View.OnClickListener() {
            @Override public void onClick(View v) {
                listener.onItemClick(item);
            }
        });
    }
}

}

In your Activity or fragment :

ContentAdapter adapter = new ContentAdapter(itemList, this);

Note : Implement the OnItemClickListener based on context given by you in activity or fragment and overide methods.

Solution 17 - Android

Short extension for Kotlin
Method returns absolute position of all items (not the position of only visible items).

fun RecyclerView.getChildPositionAt(x: Float, y: Float): Int {
    return getChildAdapterPosition(findChildViewUnder(x, y))
}

And usage

val position = recyclerView.getChildPositionAt(event.x, event.y)

Solution 18 - Android

Use getLayoutPosition() in your custom interface java method. This will return the selected position of an item, check full detail on

https://becody.com/get-clicked-item-and-its-position-in-recyclerview/

Solution 19 - Android

//simply check if the adapter position you get not less than zero

holder.btnDelItem.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if(holder.getAdapterPosition()>=0){
            list.remove(holder.getAdapterPosition());
            notifyDataSetChanged();
        }
    }
});

Solution 20 - Android

After lot of trial and error I found that there is a very easy way to do this that is by creating an interface in adapter class and implementing that in fragment now here comes the twist, I instansiated the view model inside my override function present In the fragment now you can send the data from that function to viemodel and from there anywhere.

I don't know if this method is good coding method but please let me know in comment and if any wants to see the let me know in the comment section I regularly open stackover flow.

Solution 21 - Android

recyclerView.addOnItemTouchListener(object : AdapterView.OnItemClickListener,
                RecyclerView.OnItemTouchListener {
                override fun onItemClick(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
                    TODO("Not yet implemented")
                }

                override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {
                    TODO("Not yet implemented")
                }

                override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
                    TODO("Not yet implemented")
                }

                override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
                    TODO("Not yet implemented")
                }

            })

If use Kotlin

Solution 22 - Android

In onViewHolder set onClickListiner to any view and in side click use this code :

Toast.makeText(Drawer_bar.this, "position" + position, Toast.LENGTH_SHORT).show();

Replace Drawer_Bar with your Activity name.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionXcihnegnView Question on Stackoverflow
Solution 1 - AndroidXcihnegnView Answer on Stackoverflow
Solution 2 - AndroidUday HiwaraleView Answer on Stackoverflow
Solution 3 - AndroidGilberto IbarraView Answer on Stackoverflow
Solution 4 - Androidbhumika rijiyaView Answer on Stackoverflow
Solution 5 - AndroidMazRoidView Answer on Stackoverflow
Solution 6 - AndroidAmandeep RohilaView Answer on Stackoverflow
Solution 7 - AndroidCosmin BadulescuView Answer on Stackoverflow
Solution 8 - AndroidAkanksha RathoreView Answer on Stackoverflow
Solution 9 - AndroidHimanshu NimjeView Answer on Stackoverflow
Solution 10 - AndroidMateusz NiedbalView Answer on Stackoverflow
Solution 11 - AndroidZoubiockView Answer on Stackoverflow
Solution 12 - AndroidKirill VolkovView Answer on Stackoverflow
Solution 13 - AndroidSpencer MilnerView Answer on Stackoverflow
Solution 14 - AndroidcarlView Answer on Stackoverflow
Solution 15 - AndroidKamranView Answer on Stackoverflow
Solution 16 - AndroidRajeshVijayakumarView Answer on Stackoverflow
Solution 17 - AndroidPavel ShorokhovView Answer on Stackoverflow
Solution 18 - AndroidRana AamerView Answer on Stackoverflow
Solution 19 - AndroidYasir TariqView Answer on Stackoverflow
Solution 20 - Androiduser12586023View Answer on Stackoverflow
Solution 21 - AndroidSandeep PareekView Answer on Stackoverflow
Solution 22 - AndroidThasreef MogralView Answer on Stackoverflow