Skip to content

Instantly share code, notes, and snippets.

@riyazMuhammad
Last active December 30, 2020 15:10
Show Gist options
  • Save riyazMuhammad/1c7b1f9fa3065aa5a46f to your computer and use it in GitHub Desktop.
Save riyazMuhammad/1c7b1f9fa3065aa5a46f to your computer and use it in GitHub Desktop.
Easy Implementation of RecyclerView custom onItemClickListener

#The Problem In the way of replacing ListViews with RecyclerView I hit this obstacle where there is no onItemClickListener in RecyclerView ??? And when googled, I found almost all the posts saying we have to implement this using the GestureDetector. And some of them had used interfaces which is what I too thought of using in the first place. But even they were so much confusing and complex to understand.

#Solution

Prerequisites

  1. Interfaces (Donot worry if you never used one. But they are very simple concept) - CustomItemClickListener.java
  2. ViewHolder Adapter - ItemsListAdapter.java
  3. ViewHolder Item Class - ItemsListSingleItem.java
  4. The RecyclerView Itself - ItemsList (See Setting up the RecyclerView)

Solving the problem

Consider for example you have a list of thumbnails and a title to be listed. I would do the following to keep stuff simple and working. :)

Checkout the sample project here

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/items_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
public interface CustomItemClickListener {
public void onItemClick(View v, int position);
}
public class ItemsListAdapter extends RecyclerView.Adapter<ItemsListAdapter.ViewHolder> {
ArrayList<ItemListSingleItem> data;
Context mContext;
CustomItemClickListener listener;
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View mView = LayoutInflater.from(parent.getContext()).inflate(R.layout.items_list_single_item, parent, false);
final ViewHolder mViewHolder = new ViewHolder(mView);
mView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onItemClick(v, mViewHolder.getPosition());
}
});
return mViewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.itemTitle.setText(Html.fromHtml(data.get(position).getTitle()));
if (!TextUtils.isEmpty(data.get(position).getThumbnailURL())) {
// I Love picasso library :) http://square.github.io/picasso/
Picasso.with(mContext).load(data.get(position).getThumbnailURL()).error(R.drawable.ic_no_image).
placeholder(R.drawable.ic_no_image).
transform(new RoundedCornersTransformation(5, 0)).
into(holder.thumbnailImage);
} else {
holder.thumbnailImage.setImageResource(R.drawable.ic_no_image);
}
}
@Override
public int getItemCount() {
return data.size();
}
public ItemsListAdapter(Context mContext, ArrayList<ItemsListSingleItem> data, CustomItemClickListener listener) {
this.data = data;
this.mContext = mContext;
this.listener = listener;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView itemTitle;
public ImageView thumbnailImage;
ViewHolder(View v) {
super(v);
itemTitle = (TextView) v
.findViewById(R.id.post_title);
thumbnailImage = (ImageView) v.findViewById(R.id.post_thumb_image);
}
}
}
public class ItemsListSingleItem {
private String title,thumbnailURL;
/**
* Just for the sake of internal reference so that we can identify the item.
*/
long id;
/**
*
* @param id
* @param title
* @param thumbnailURL
*/
public ItemsListSingleItem(long id, String title, String thumbnailURL) {
this.id = id;
this.title = title;
this.thumbnailURL = thumbnailURL;
}
public String getTitle() {
return title;
}
public long getID() {
return id;
}
public String getThumbnailURL() {
return thumbnailURL;
}
}
public class HomeActivity extends AppCompatActivity{
RecyclerView itemsList;
ItemsListAdapter adapter;
ArrayList<ItemsListSingleItem> data = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
itemsList = (RecyclerView) getView().findViewById(R.id.items_list);
itemsList.setHasFixedSize(true);
mLinearLayoutManager = new LinearLayoutManager(this);
itemsList.setLayoutManager(mLinearLayoutManager);
//let us add some items into the list
data.add(
new ItemsListSingleItem(
1,
"First Item",
"www.someUrlToMyThumbnailImage1"
));
data.add(
new ItemsListSingleItem(
2,
"Second Item",
"www.someUrlToMyThumbnailImage2"
));
adapter = new ItemsListAdapter(getActivity(), data, new CustomItemClickListener() {
@Override
public void onItemClick(View v, int position) {
Log.d(TAG, "clicked position:" + position);
long postId = data.get(position).getID();
// do what ever you want to do with it
}
});
itemsList.setAdapter(adapter);
}
}
@kelkarneha
Copy link

Thank you very much for this solution!

@kelkarneha
Copy link

Thank you very much for this solution!

@kelkarneha
Copy link

Thank you very much for this solution!

@kelkarneha
Copy link

Thank you very much for this solution!

Copy link

ghost commented May 5, 2016

Thanks man. I also made another interface called CustomItemHoldListener the same way you did. It's ridiculous that you even need to this, ListView was so much simpler! Oh well.

@alashow
Copy link

alashow commented Sep 24, 2016

mViewHolder.getPosition() is deprecated.
ItemListAdapter.java:14:
listener.onItemClick(v, mViewHolder.getPosition());
to
listener.onItemClick(v, mViewHolder.getAdapterPosition());

@denisvasyanin
Copy link

Thanks man

@iRajul
Copy link

iRajul commented Mar 12, 2017

I am getting error
Class 'Anonymous class derived from CustomItemClickListener' must either be declared abstract or implement abstract method 'onItemClick(HomeOptions, int)' in 'CustomItemClickListener'

@cjoseanguiano
Copy link

Muchas Gracias 👍

Copy link

ghost commented Apr 29, 2017

This solution didn't work for me - every time my ClickListener returned index "-1".
The solution was change the place of implementing internal onClick method (in ItemViewHolder internal class, not in Adapter), like:
`public class MovieViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {

    public TextView title;
    public TextView year;
    public TextView genre;

    public MovieViewHolder(View view) {
        super(view);
        title = (TextView) view.findViewById(R.id.list_row_title);
        genre = (TextView) view.findViewById(R.id.list_row_genre);
        year = (TextView) view.findViewById(R.id.list_row_year);
        view.setOnClickListener(this);
        view.setOnLongClickListener(this);
    }

    @Override
    public void onClick(View v) {
        listener.onItemClick(v, this.getAdapterPosition());

// Log.d("ItemID", String.valueOf(this.getItemId()));
// Log.d("ItemLayoutPosition", String.valueOf(this.getLayoutPosition()));
// Log.d("ItemAdapterPosition", String.valueOf(this.getAdapterPosition()));
}

    @Override
    public boolean onLongClick(View v) {
        listener.onItemLongClick(v, this.getAdapterPosition());
        return true;
    }
}`

@JoCodes
Copy link

JoCodes commented May 29, 2017

Your solution is perfect for Recyclerview click. But can you please let me know how can we handle individual item clicks ( 2 buttons inside the RecyclerView ) like the below
adapter = new ItemsListAdapter(getActivity(), data, new CustomItemClickListener() {
@OverRide
public void onItemClick(View v, int position) {
Log.d(TAG, "clicked position:" + position);
long postId = data.get(position).getID();
// which button clicked and separate action for each button
}
});

@henguel19
Copy link

Thank you, your code help me so much

@PatelJay017
Copy link

Its Good, But i Want to Pass Array Adpter to Recyclerview Using Interface, So How Can I do?

@abdulbasit12345
Copy link

abdulbasit12345 commented Feb 6, 2018

i have a problem whit RoundedCornerTransformation()...what is this....onBindViewHolder() methods....

@AYLB
Copy link

AYLB commented Mar 7, 2018

Excellent, this solution is easy and help me so much :) thank you

@ganesha96
Copy link

Those Looking to add different button to different activities

    adapter = new CategoryAdapter(this, categoryList, new CustomItemClickListener() {
        @Override
        public void onItemClick(View v, int position) {
            long postId = categoryList.get(position).getID();
            if (postId == 1){
                Intent intent = new Intent(MainActivity.this, NewActivity.class);
                startActivity(intent);
            } else if (postId == 2){
                Intent intent1 = new Intent(MainActivity.this,  NewActivity1.class);
                startActivity(intent1);
            } else if (postId == 3){
                Intent intent2 = new Intent(MainActivity.this,  NewActivity2.class);
                startActivity(intent2);
            }
        }
    });
    recyclerView.setAdapter(adapter);

@porya74
Copy link

porya74 commented Feb 21, 2019

good solution, but I'm not sure about how the position gets where the CustomItemClickListener passed out as an argument in HomeActivity.(the code snippet below)
can anyone leave an explanation?

adapter = new ItemsListAdapter(getActivity(), data, new CustomItemClickListener() { @Override public void onItemClick(View v, int position) { Log.d(TAG, "clicked position:" + position); long postId = data.get(position).getID(); // do what ever you want to do with it } }); itemsList.setAdapter(adapter); }

@er361
Copy link

er361 commented Jun 11, 2019

thx help a lot
i am new in java so create iface and view on click it's kind of magical for me
but seems awesome!!!

@daniilkofficial
Copy link

Good idea!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment