Reputation: 6798
Has anyone using RecyclerView
found a way to set an onClickListener
to items in the RecyclerView
?
I thought of setting a listener to each of the layouts for each item but that seems a little too much hassle
I'm sure there is a way for the RecyclerView
to listen for the onClick
event but I can't quite figure it out.
Upvotes: 678
Views: 809313
Reputation: 1575
I do it in this way, without undue classes, detectors etc. Simple code inside our adapter. Especially better solution for longClick than presented before.
public class PasswordAdapter extends RecyclerView.Adapter<PasswordAdapter.ViewHolder> {
private final ClickListener clickListener;
public PasswordAdapter(ClickListener clickListener) {
this.clickListener = clickListener;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
TextView name;
public ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
name = (TextView) itemView.findViewById(R.id.card_name);
}
@Override
public void onClick(View v) {
int position = getBindingAdapterPosition();
if (position >= 0) {
clickListener.onItemClick(position, v);
}
}
@Override
public boolean onLongClick(View v) {
int position = getBindingAdapterPosition();
if (position >= 0) {
clickListener.onItemLongClick(position, v);
return true;
}
return false;
}
}
public interface ClickListener {
void onItemClick(int position, View v);
void onItemLongClick(int position, View v);
}
}
Then inside fragment or activity, just hit:
PasswordAdapter mAdapter = new PasswordAdapter(
new PasswordAdapter.ClickListener() {
@Override
public void onItemClick(int position, View v) {
Log.d(TAG, "onItemClick position: " + position);
}
@Override
public void onItemLongClick(int position, View v) {
Log.d(TAG, "onItemLongClick pos = " + position);
}
}
);
Upvotes: 130
Reputation: 4388
Here is my code snippet:
v.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
int newPosition = MainActivity.mRecyclerView.getChildAdapterPosition(v);
Intent cardViewIntent = new Intent(c, MainActivityCards.class);
cardViewIntent.putExtra("Position", newPosition);
c.startActivity(cardViewIntent);
}
});
v
is View from onCreateViewHolder
c
is ContextUpvotes: 1
Reputation: 1583
Setup click listener inside your ViewHolder
this way:
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title, year, genre;
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.title);
genre = (TextView) view.findViewById(R.id.genre);
year = (TextView) view.findViewById(R.id.year);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, ""+getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
});
}
}
Upvotes: 4
Reputation: 5349
For kotlin handle click on RecyclerView
answer based on Jacobs answer
Create class RecyclerItemClickListener
:
class RecyclerItemClickListener(context: Context, recyclerView: RecyclerView, listner: OnItemClickListener) : RecyclerView.OnItemTouchListener {
var mGestureDetector: GestureDetector
var mListner: OnItemClickListener
interface OnItemClickListener {
fun onItemClick(view: View, position: Int)
fun onLongItemClick(view: View, position: Int)
}
init {
this.mListner = listner
mGestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(e: MotionEvent?): Boolean = true
override fun onLongPress(e: MotionEvent?) {
val child: View? = recyclerView.findChildViewUnder(e!!.getX(), e.getY())
if (child != null && mListner != null) {
mListner.onLongItemClick(child, recyclerView.getChildAdapterPosition(child))
}
}
})
}
override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) = Unit
override fun onInterceptTouchEvent(view: RecyclerView, e: MotionEvent): Boolean {
val childView: View? = view.findChildViewUnder(e!!.getX(), e.getY())
if (childView != null && mListner != null && mGestureDetector.onTouchEvent(e)) {
mListner.onItemClick(childView, view.getChildAdapterPosition(childView))
return true
}
return false
}
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) = Unit
}
Get click on Any RecyclerView
(inside activity/fragment):
recyclerView.addOnItemTouchListener(
RecyclerItemClickListener(this, recyclerView, object : RecyclerItemClickListener.OnItemClickListener {
override fun onItemClick(view: View, position: Int) {
// TODO catch click
}
override fun onLongItemClick(view: View, position: Int) {
// TODO catch click
}
})
)
Upvotes: 0
Reputation: 23404
This is what I do to reuse View.OnClickListener
:
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.MyviewHolder>
implements View.OnClickListener
In ViewHoder
take parent view of item layout:
public class MyviewHolder extends RecyclerView.ViewHolder {
LinearLayout linearLayout;
public MyviewHolder(View itemView) {
super(itemView);
linearLayout = itemView.findViewById(R.id.linear_layout_item);
}
}
In onBindViewHolder
set tag as position:
@Override
public void onBindViewHolder(MyviewHolder holder, int position) {
holder.linearLayout.setTag(position);
holder.linearLayout.setOnClickListener(this);
}
And inside your onClick
realization:
@Override
public void onClick(View v) {
int position = (int) v.getTag();
switch (v.getId()) {
case R.id.linear_layout_item:
// do some thing with position
break;
}
}
Upvotes: 2
Reputation: 360
In kotlin with constructor implementation
Initialize your RecyclerView
constructor like below:
class ListAdapter(
c: Context,
private var list: List<Project>,
private val itemClick: (Project) -> Unit
) : RecyclerView.Adapter<ListAdapter.ViewHolder>()
return with itemClick
in your onCreateViewHolder
:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):ProjectViewHolder {
val view = inflater.inflate(R.layout.list_item, parent, false)
return ViewHolder(view, itemClick)
}
Your onBindViewHolder
:
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindProject(list[position])
}
Then with ViewHolder
class create bindProject
function.
class ViewHolder(
view: View,
private val itemClick: (Project) -> Unit
) : RecyclerView.ViewHolder(view) {
private val clientTextCount = 7
val titleTextView: TextView = view.projectTitleTextView
fun bindProject(project: Project) {
with(project) {
titleTextView.text = name
itemView.setOnClickListener { itemClick(this) }
}
}
}
Finally in your activity initialize adapter with lazy
private val adapter: ListAdapter by lazy {
ListAdapter(this, projectList, {
// Here you can implement your onClick function.
})
}
For adding new list to RecyclerView
initialize below method in your adapter:
fun setProjects(projects: List<Project>) {
projectList = projects
notifyDataSetChanged()
}
And call setProjects
method anywhere in your activity:
adapter.setProjects(projects)
That's it.
Upvotes: 2
Reputation: 13139
According to Yigit Boyar, the best way to register a click on a RecyclerView
is to define the click in the creation of the ViewHolder
instead of just creating a new onClickListener
for each item that the onBindViewHolder
binds
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
val itemBinding = LayoutInflater.from(context).inflate(R.layout.my_layout, parent, false)
val vh = MainViewHolder (itemBinding)
vh.itemView.setOnClickListener {
val pos = vh.adapterPosition
if(pos != NO_POSITION){
itemClickLister.onCocktailClick(myList[pos],pos)
}
}
return vh
}
Upvotes: 7
Reputation: 619
I have developed a light weighted library for android, you can visit github and follow this sample:
RecycleClick.addTo(YOUR_RECYCLE_VIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
// Your code here
}
});
Upvotes: 7
Reputation: 758
Try this, simple enough. It works for me. BTW, I found that setOnClickListener
doesn't take effect for RecyclerView
.
recycler.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
// anything todo
}
return true;
}
});
Upvotes: 0
Reputation: 11921
You can implement View.OnClickListener
to your ViewHolder
class
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public Item item
@InjectView(R.id.tv_title)
public TextView tvTitle;
@InjectView(R.id.rl_row)
public RelativeLayout rlRow;
public ViewHolder(View v) {
super(v);
ButterKnife.inject(this, v);
v.setOnClickListener(this);
}
@Override
public void onClick(View view) {
Log.e("item title",item.getTitle());
}
}
And onBindViewHolder
set your view holder's item:
public void onBindViewHolder(ViewHolder holder, int position) {
holder.tvTitle.setText(objects.get(position).getTitle());
holder.item = objects.get(position);
}
Upvotes: 7
Reputation: 2864
Check out a similar question @CommonsWare's comment links to this, which implements the OnClickListener
interface in the viewHolder
.
Here's a simple example of the ViewHolder
:
/** Declare global with in adapter class. */
TextView textView;
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
textView = (TextView) view.findViewById(android.R.id.text1);
}
@Override
public void onClick(View view) {
Toast.makeText(view.getContext(), "position = " + getLayoutPosition(), Toast.LENGTH_SHORT).show();
/** Go through each item if you have few items within RecyclerView. */
if (getLayoutPosition() == 0) {
// Do whatever you want here
} else if(getLayoutPosition() == 1) {
// Do whatever you want here
} else if(getLayoutPosition() == 2) {
// Do whatever you want here
}
/** Or you can use For loop if you have long list of items. */
for (int i = 0; i < exampleList.size(); i++) {
// Do whatever you want here
}
}
}
The creation of ViewHolder
inside your RecyclerView.Adapter
then looks like this:
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext())
View view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
return new ViewHolder(view);
}
Upvotes: 103
Reputation: 571
In your activity class:
class YourActivity : AppCompatActivity(), TestAdapter.ClickListener {
...
override fun itemClicked() {
}
...
}
In your adapter class:
class MyAdapter : RecyclerView.Adapter<MyAdapter.MyViewHolder> {
...
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.textView1.setOnClickListener {
clickListener.itemClicked(position)
}
}
...
interface ClickListener {
fun itemClicked(position : Int)
}
...
}
In your adapter class:
class MyAdapter(val callBack: (pos:Int) -> Unit) : RecyclerView.Adapter<MyAdapter.MyViewHolder> {
...
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.textView1.setOnClickListener {
callBack(position)
}
}
}
In your activity class:
class YourActivity : AppCompatActivity() {
...
val testAdapter = TestAdapter(
callBack = { index ->
})
binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = testAdapter
...
}
Upvotes: 0
Reputation: 5561
You can easily define setOnClickListener
in your ViewHolder
class as follow:
public class ViewHolder extends RecyclerView.ViewHolder {
TextView product_name;
ViewHolder(View itemView) {
super(itemView);
product_name = (TextView) itemView.findViewById(R.id.product_name);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int itemPosition = getLayoutPosition();
Toast.makeText(getApplicationContext(), itemPosition + ":" + String.valueOf(product_name.getText()), Toast.LENGTH_SHORT).show();
}
});
}
}
Upvotes: 6
Reputation: 31801
Don't reinvent the wheel! The code for this specific use case is included in the Master/Detail Flow starter project that comes with Android Studio.
From Android Studio select:
I am not going to include here the code from google's ootb the demo project, but I'll outline the main design approaches in the sample provided by google:
RecyclerView.Adapter
implementation.onBindViewHolder()
you should set the same, pre-created onClickListener object on your ViewHolder instance with holder.itemView.setOnClickListener(mOnClickListener)
(AVOID creating a new instance on every method call!); if you need to capture clicks on some specific elements inside the ViewHolder then extend ViewHolder and expose the elements you need as fields so that you can attach whatever listeners you need in onBindViewHolder()
— and once again, do NOT re-create the listeners on every method call — initialise them as instance fields and attach them as needed..setTag()
in order to pass state to your viewHolder, e.g. holder.itemView.setTag(mValues.get(position));
as used in the demo.Upvotes: 4
Reputation: 4649
I have nice solution for RecyclerView
's onItemClickListener
for the items and subitems
Step 1- Create an interface
public interface OnRecyclerViewItemClickListener
{
/**
* Called when any item with in recyclerview or any item with in item
* clicked
*
* @param position
* The position of the item
* @param id
* The id of the view which is clicked with in the item or
* -1 if the item itself clicked
*/
public void onRecyclerViewItemClicked(int position, int id);
}
Step 2- Then use it in adapter's onBindViewHolder
method in the following way
/**
* Custom created method for Setting the item click listener for the items and items with in items
* @param listener OnRecyclerViewItemClickListener
*/
public void setOnItemClickListener(OnRecyclerViewItemClickListener listener)
{
this.listener = listener;
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, final int position)
{
// viewHolder.albumBg.setBackgroundResource(_itemData[position]
// .getImageUrl());
viewHolder.albumName.setText(arrayList.get(position).getName());
viewHolder.artistName.setText(arrayList.get(position).getArtistName());
String imgUrl = arrayList.get(position).getThumbImageUrl();
makeImageRequest(imgUrl, viewHolder);
viewHolder.parentView.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
listener.onRecyclerViewItemClicked(position, -1);
}
});
viewHolder.settingButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
listener.onRecyclerViewItemClicked(position, v.getId());
}
});
}
// class to hold a reference to each item of RecyclerView
public static class ViewHolder extends RecyclerView.ViewHolder
{
public TextView albumName, artistName;
public ImageView albumIcon, settingButton;
public LinearLayout parentView;
public ViewHolder(View itemLayoutView)
{
super(itemLayoutView);
// albumBg = (LinearLayout) itemLayoutView
// .findViewById(R.id.albumDlbg);
albumName = (TextView) itemLayoutView.findViewById(R.id.albumName);
artistName = (TextView) itemLayoutView
.findViewById(R.id.artistName);
albumIcon = (ImageView) itemLayoutView.findViewById(R.id.albumIcon);
parentView = (LinearLayout) itemLayoutView
.findViewById(R.id.albumDlbg);
settingButton = (ImageView) itemLayoutView
.findViewById(R.id.settingBtn);
}
}
Step 3- find and setup recycler view in activity or fragment where you are using this
recyclerView = (RecyclerView) rootview.findViewById(R.id.vmtopsongs);
lm = new LinearLayoutManager(mActivity);
lm.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(lm);
recyclerView.addItemDecoration(
new HorizontalDividerItemDecoration.Builder(getActivity())
.paint(Utils.getPaint()).build());
PopularSongsadapter mAdapter = new PopularSongsadapter(gallery,
mActivity, true);
// set adapter
recyclerView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(this);
// set item animator to DefaultAnimator
recyclerView.setItemAnimator(new DefaultItemAnimator());
Step 4- Finally implement interface in activity or fragment where you are using the recyclerview
@Override
public void onRecyclerViewItemClicked(int position, int id)
{
if(id==-1){
Toast.makeText(mActivity, "complete item clicked", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(mActivity, "setting button clicked", Toast.LENGTH_LONG).show();
}
}
Update for Kotlin Language I have updated the code for kotlin in which only whole view has on click listener. You can set subitems click listener by editing interface and code according to above java code.
Adapter
class RecentPostsAdapter(private val list: MutableList<Post>) :
RecyclerView.Adapter<RecentPostsAdapter.ViewHolder>() {
private lateinit var onItemClickListener: OnItemClickListener
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.listitem_recent_post, parent, false)
)
}
override fun getItemCount(): Int {
return list.size
}
fun setOnItemClickListener(onItemClickListener: OnItemClickListener) {
this.onItemClickListener = onItemClickListener
}
private fun getItem(position: Int): Post {
return list[position]
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
holder.itemView.setOnClickListener(View.OnClickListener {
onItemClickListener.onItemClick(
position
)
})
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private var imageView: NetworkImageView? = null
private var tvTitle: TextView? = null
private var tvExcerpt: TextView? = null
private var htmlSpanner: HtmlSpanner = HtmlSpanner()
init {
imageView = itemView.findViewById(R.id.niv_post_image)
tvTitle = itemView.findViewById(R.id.tv_post_title)
tvExcerpt = itemView.findViewById(R.id.tv_post_excerpt)
}
fun bind(post: Post) {
tvTitle?.text = post.title
tvExcerpt?.text = htmlSpanner.fromHtml(post.excerpt)
}
}
interface OnItemClickListener {
fun onItemClick(position: Int)
}
}
Activity or Fragment
recyclerView = view.findViewById(R.id.rvHomeRecentPosts)
recyclerView.layoutManager = LinearLayoutManager(view.context)
list = mutableListOf()
recentPostsAdapter = RecentPostsAdapter(list)
recyclerView.adapter = recentPostsAdapter
recentPostsAdapter.setOnItemClickListener(object:RecentPostsAdapter.OnItemClickListener{
override fun onItemClick(position: Int) {
(activity as MainActivity).findNavController(R.id.nav_host_fragment).navigate(R.id.action_nav_home_to_nav_post_detail)
}
})
Upvotes: 40
Reputation: 339
This works.
public class ServiceListAdapter extends RecyclerView.Adapter<ServiceListAdapter.ViewHolder> {
private final Context mContext;
private List<ServiceListModel> categoryList;
private View.OnClickListener onClickListener;
public ServiceListAdapter(Context mContext, List<ServiceListModel> categoryList, View.OnClickListener onClickListener) {
this.categoryList = categoryList;
this.mContext = mContext;
this.onClickListener = onClickListener;
}
@Override
public ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
final RowServiceListBinding binding = DataBindingUtil.inflate(inflater, R.layout.row_service_list, parent, false);
return new ViewHolder(binding.getRoot(), binding);
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
holder.binding.rlService.setOnClickListener(onClickListener);
holder.binding.rlService.setTag(position);
}
@Override
public int getItemCount() {
return categoryList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private final RowServiceListBinding binding;
public ViewHolder(final View view, final RowServiceListBinding binding) {
super(view);
this.binding = binding;
}
@UiThread
public void bind(final ServiceListModel mAddressModel) {
//this.binding.setAddress(mAddressModel);
}
}
}
Use in activity/fragment
ServiceListAdapter adapter = new ServiceListAdapter(context, serviceList, new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.rlService:
int pos = (int) v.getTag();
serviceList.remove(position);
break;
}
}
});
Upvotes: -1
Reputation: 799
Add an interface in your adapter class.
public interface SelectedUser{
void selectedUser(UserModel userModel);
}
implement your interface in the mainactivity and overide selectedUser method.
@Override
public void selectedUser(UserModel userModel) {
startActivity(new Intent(MainActivity.this, SelectedUserActivity.class).putExtra("data",userModel));
}
Full tutorial check out here plus source code. Recyclerview with clicklistener and searchview
Upvotes: 2
Reputation: 493
here my way
in activity class:
public class MyActivity extends AppCompatActivity implements EmployeeAdapter.ClickListener {
...
@Override
public void onClick(int position) { ... }
...
}
in adapter class:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
...
@Override
public void onBindViewHolder(){
holder.textView1.setOnClickListener(v -> clickListener.onClick(position));
}
...
public interface ClickListener {
void onClick(int position);
}
...
}
Upvotes: 0
Reputation: 1040
This was so hard for me to have on item click listener in the activity and also to have click listener for single view of the item that will not trigger on item click listener. After playing around with Jacob Tabak's answer I respect his answer for on item click if no other touch actions inside item are presented.
I have a custom OnClickListener
interface that have on item click event which holds the clicked item's view and the item position from the adapter. I present an instance of it in the constructor(or it can be with setter) and attach it to the view holder container click listener.
I also have other click listener in the Adapter(Can be in the view holder) which will handle current View click from the container.
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyViewHolder> {
private ArrayList<String> mData;
private OnItemClickListener mOnItemClickListener;
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
public MyRecyclerAdapter(ArrayList<String> itemsData,
OnItemClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
this.mData = itemsData;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View layoutView = LayoutInflater.from(mContext).inflate(
R.layout.list_item, parent, false);
final MyViewHolder viewHolder = new MyViewHolder(layoutView);
viewHolder.container.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onItemClick(v, viewHolder.getAdapterPosition());
}
});
viewHоlder.button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//do button click work here with
// mData.get( viewHolder.getAdapterPosition() );
}
});
return viewHolder;
}
@Override
public int getItemCount() {
return mData.size();
}}
In the activity you need to initialize the adapter by passing instance of the OnItemClickListener
public class FeedActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
.....
MyRecyclerAdapter adapter = new MyRecyclerAdapter(new ArrayList<String>(), new OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
///list item was clicked
}
});
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(mFeedsAdapter);
}
And my ViewHolder
public class MyViewHolder extends RecyclerView.ViewHolder {
public Button button;
public View container;
public MyViewHolder(View itemLayoutView) {
super(itemLayoutView);
container = itemLayoutView;
button = (Button) itemLayoutView.findViewById(R.id.button);
}}
Upvotes: 55
Reputation: 840
Let's see how we can also implement this with Jetpack / AndroidX
You need to create an observable in the viewmodel class like this
private MutableLiveData<Integer> adapterItem = new MutableLiveData<>();
public MutableLiveData<Integer> getAdapterItem() {
return adapterItem;
}
public void setAdapterItem(int adapterItem) {
this.getAdapterItem().setValue(adapterItem);
}
Then in the adapter class make sure you pass the viewmodel reference as parameter in the constructor then implement the clicklistener on the viewholder
public MyViewHolder(@NonNull View itemView) {
super(itemView);
if(itemView != null){
itemView.setOnClickListener(v -> {
int adapterPosition = getAdapterPosition();
viewModel.setAdapterItem(adapterPosition);
});
};
}
Then from the activity class just observe the changes
viewModel.getAdapterItem().observe(this, position -> {
Log.w(TAG, "clicked: " + ridesArray.get(position));
});
Upvotes: 0
Reputation: 1183
Here is simple and clear way is add inside your ReacyclerView
ViewHolder
public static class MyViewholder extends RecyclerView.ViewHolder {
public MyViewholder(View itemView) {
super(itemView);
itemView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Tag", "onClick:" + getAdapterPosition());
}
});
}
}
getAdapterPosition()
is returns the current clicked item position
Upvotes: 4
Reputation: 31
here is complete code for my custom adapter this code will inflate the rows with list items defined in the xml file named "list_item" it will also perform click event on all list items rows with respective positions.
public class MyCustomAdapter extends RecyclerView.Adapter`<`AdapterMyCustomAdapter.ViewHolder> {
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public onItemClickListener mListener;
public ViewHolder(View v, onItemClickListener listener) {
super(v);
mListener =listener;
v.setOnClickListener(this);
}
@Override
public void onClick(View v) {
mListener.onRecyclerItemClick(v, getPosition());
}
public static interface onItemClickListener {
public void onRecyclerItemClick(View view , int position);
}
}
@Override
public int getItemCount() {
return 5;
}
@Override
public void onBindViewHolder(ViewHolder holder, int pos) {
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
/* here list_item is an xml file we want to inflate ...it is same as we do in case of listview for customization.*/
MyCustomAdapter.ViewHolder vh = new ViewHolder(v, new MyCustomAdapter.ViewHolder.onItemClickListener() {
@Override
public void onRecyclerItemClick(View view, int position) {
System.out.println("clicked on list item at position " +position);
}
});
return vh;
}
}
Upvotes: 3
Reputation: 627
For me the clean way to do that is this one.
Adapter constructor
private class EnvironmentTypeRecyclerViewAdapter extends RecyclerView.Adapter<EnvironmentTypeRecyclerViewAdapter.ViewHolder>
{
private final EnvironmentTypeRecyclerViewAdapterListener mEnvironmentTypeRecyclerViewAdapterListener;
private List<Environment> mEnvironmentsData;
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
public ViewHolder(View v)
{
super(v);
v.setOnClickListener(this);
}
@Override
public void onClick(View v)
{
Environment environment = mEnvironmentsData.get(getAdapterPosition());
if (mEnvironmentTypeRecyclerViewAdapterListener != null && environment != null) {
mEnvironmentTypeRecyclerViewAdapterListener.onListItemSelected(environment);
}
}
public EnvironmentTypeRecyclerViewAdapter(List<SmallCellEnvironment> environments, EnvironmentTypeRecyclerViewAdapterListener environmentTypeRecyclerViewAdapterListener)
{
mEnvironmentTypeRecyclerViewAdapterListener = environmentTypeRecyclerViewAdapterListener;
mEnvironmentsData = environments;
}
}
The Linked Interface
private interface EnvironmentTypeRecyclerViewAdapterListener
{
void onListItemSelected(Environment environment);
}
Upvotes: 2
Reputation: 1266
I have looked thorugh all of the anwers and was not quite satasifed. I found much easier and faster solution. Wanted to share for future readers.
View
inside your single recycler item. View
(Make sure you cast to appropirate ViewGroup
)onClickListener
to this parent. Sample code (It is written inside your onBindViewHolder
method of your adapter
):
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
ConstraintLayout parent = (ConstraintLayout) holder.title.getParent();
parent.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, "Clicked recycler view item at position " + position, Toast.LENGTH_SHORT).show();
}
});
}
Upvotes: 1
Reputation: 2942
Here is what I did Read more & download the gist here
Adding the same here
CustomItemClickListener.java
public interface CustomItemClickListener {
public void onItemClick(View v, int position);
}
ItemsListAdapter.java
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.getAdapterPosition());
}
});
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);
}
}
}
Upvotes: 5
Reputation: 2985
Kotlin implementation of nhaarman's answer :
mRecyclerView.addOnItemTouchListener(object : RecyclerItemClickListener(this, mRecyclerView,object :RecyclerItemClickListener.OnItemClickListener{
override fun onItemClick(view: View, position: Int) {
}
override fun onLongItemClick(view: View?, position: Int) {
}
}){})
RecyclerItemClickListener.java :
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
open class RecyclerItemClickListener(context: Context, recyclerView: RecyclerView, private val mListener: OnItemClickListener?) : RecyclerView.OnItemTouchListener {
private var mGestureDetector: GestureDetector
interface OnItemClickListener {
fun onItemClick(view: View, position: Int)
fun onLongItemClick(view: View?, position: Int)
}
init {
mGestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(e: MotionEvent): Boolean {
return true
}
override fun onLongPress(e: MotionEvent) {
val child = recyclerView.findChildViewUnder(e.x, e.y)
if (child != null && mListener != null) {
mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child))
}
}
})
}
override fun onInterceptTouchEvent(view: RecyclerView, e: MotionEvent): Boolean {
val childView = view.findChildViewUnder(e.x, e.y)
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
mListener.onItemClick(childView, view.getChildAdapterPosition(childView))
return true
}
return false
}
override fun onTouchEvent(view: RecyclerView, motionEvent: MotionEvent) {}
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
}
Upvotes: 4
Reputation: 2990
This is what I ended up needing, in case someone finds it useful:
public static class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View item) {
super(item);
item.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("RecyclerView", "onClick:" + getAdapterPosition());
}
});
}
}
Source: http://blog.csdn.net/jwzhangjie/article/details/36868515
Upvotes: 43
Reputation: 3983
Same answer in Kotlin
inner class MyViewHolder(v: View, myOnClickListener: MyOnClickListener) : RecyclerView.ViewHolder(v) {
init {
v.setOnClickListener { v -> myOnClickListener.onClick(v, adapterPosition) }
}
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.myview, viewGroup, false)
return MyViewHolder(view, mOnClickListener)
}
inner class MyOnClickListener {
fun onClick(view: View, position: Int) {
val item = mList[position]
Toast.makeText(view.context, item, Toast.LENGTH_LONG).show()
}
}
Upvotes: 0
Reputation: 440
Step 1 ) Write the click interface
Create an interface named RecyclerViewClickListener.java and add below code. Here we declare two methods onClick and onLongClick to identify item click and long click respectively.
package com.androidtutorialshub.recyclerviewtutorial.Helper;
import android.view.View;
public interface RecyclerViewClickListener {
void onClick(View view, int position);
void onLongClick(View view, int position);
}
Step 2 ) Write the Item Touch Class
Create a class named RecyclerViewTouchListener.java and add below code . Here we write the logic to detect click and long press on recycler view item .
package com.androidtutorialshub.recyclerviewtutorial.Helper;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
public class RecyclerViewTouchListener implements RecyclerView.OnItemTouchListener{
private GestureDetector gestureDetector;
private RecyclerViewClickListener clickListener;
public RecyclerViewTouchListener(Context context, final RecyclerView recyclerView, final RecyclerViewClickListener clickListener) {
this.clickListener = clickListener;
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
@Override
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null) {
clickListener.onLongClick(child, recyclerView.getChildPosition(child));
}
}
});
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
clickListener.onClick(child, rv.getChildPosition(child));
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
Step 3 ) Defining click listener
Open MainActivity.java and update the below changes. Here onClick() method will detect click on item and onLongClick will detect long click on item.
recyclerView.addOnItemTouchListener(new RecyclerViewTouchListener(getApplicationContext(), recyclerView, new RecyclerViewClickListener() {
@Override
public void onClick(View view, int position) {
Toast.makeText(getApplicationContext(), bookList.get(position).getTitle() + " is clicked!", Toast.LENGTH_SHORT).show();
}
@Override
public void onLongClick(View view, int position) {
Toast.makeText(getApplicationContext(), bookList.get(position).getTitle() + " is long pressed!", Toast.LENGTH_SHORT).show();
}
}));
For more info or Download source code :- http://www.androidtutorialshub.com/android-recyclerview-click-listener-tutorial/
Upvotes: 0
Reputation: 100448
As the API's have radically changed, It wouldn't surprise me if you were to create an OnClickListener
for each item. It isn't that much of a hassle though. In your implementation of RecyclerView.Adapter<MyViewHolder>
, you should have:
private final OnClickListener mOnClickListener = new MyOnClickListener();
@Override
public MyViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.myview, parent, false);
view.setOnClickListener(mOnClickListener);
return new MyViewHolder(view);
}
The onClick
method:
@Override
public void onClick(final View view) {
int itemPosition = mRecyclerView.getChildLayoutPosition(view);
String item = mList.get(itemPosition);
Toast.makeText(mContext, item, Toast.LENGTH_LONG).show();
}
Upvotes: 525