Java RecyclerView OnClickListener(最佳实践方式)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/49969278/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
RecyclerView OnClickListener (Best practice way)
提问by Amir Dora
I use RecyclerView
adapter to display data inside an activity, I want to implement onClickListener
inside the activity, currently, I am setting onClickListener
inside adapter as usual which works fine.
我使用RecyclerView
适配器在活动内显示数据,我想onClickListener
在活动内实现,目前,我onClickListener
像往常一样在适配器内设置,效果很好。
public void onBindViewHolder(MyHolder holder, final int position) {
final Listdata data = listdata.get(position);
holder.vname.setText(data.getName());
holder.vname.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(activity, "clicked on " +position, Toast.LENGTH_SHORT).show();
}
});
}
However I want to implement it inside activity so I have greater control. This doesn't serve my purpose. I think it'll be useful for a lot of us.
但是我想在活动中实现它,所以我有更大的控制权。这不符合我的目的。我认为这对我们很多人都有用。
采纳答案by Reaz Murshed
You need to check this tutorialhere for better understanding on how you can achieve the behaviour that you want.
您需要在此处查看本教程,以便更好地了解如何实现所需的行为。
In case of handling the onClickListener
from your activity you need to work based on a callback implementation with an interface. Pass the interface from the activity to your adapter and then call the callback function from your adapter when some items are clicked.
在处理onClickListener
来自您的活动的情况下,您需要基于带有接口的回调实现进行工作。将接口从活动传递到您的适配器,然后在单击某些项目时从您的适配器调用回调函数。
Here's a sample implementation from the tutorial.
这是教程中的示例实现。
Let us first have the interface.
让我们先来看看界面。
public interface OnItemClickListener {
void onItemClick(ContentItem item);
}
You need to modify your adapter to take the listener as the parameter like the one stated below.
您需要修改您的适配器以将侦听器作为参数,如下所述。
private final List<ContentItem> items;
private final OnItemClickListener listener;
public ContentAdapter(List<ContentItem> items, OnItemClickListener listener) {
this.items = items;
this.listener = listener;
}
Now in your onBindViewHolder
method, set the click listener.
现在在您的onBindViewHolder
方法中,设置单击侦听器。
@Override public void onBindViewHolder(ViewHolder holder, int position) {
holder.bind(items.get(position), listener);
}
public void bind(final ContentItem item, final OnItemClickListener listener) {
...
itemView.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
listener.onItemClick(item);
}
});
}
Now setting the adapter in your RecyclerView
.
现在在您的RecyclerView
.
recycler.setAdapter(new ContentAdapter(items, new ContentAdapter.OnItemClickListener() {
@Override public void onItemClick(ContentItem item) {
Toast.makeText(getContext(), "Item Clicked", Toast.LENGTH_LONG).show();
}
}));
So the whole adapter code looks like the following.
所以整个适配器代码如下所示。
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);
Picasso.with(itemView.getContext()).load(item.imageUrl).into(image);
itemView.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
listener.onItemClick(item);
}
});
}
}
}
回答by ADM
You can let your Activity
implements View.OnClickListener
and pass it to adapter. Below is an example.
您可以让您的Activity
工具View.OnClickListener
并将其传递给适配器。下面是一个例子。
class RAdapter extends RecyclerView.Adapter<>{
View.OnClickListener listner;
public RAdapter(View.OnClickListener listner) {
this.listner = listner;
}
public void onBindViewHolder(MyHolder holder, final int position) {
holder.vname.setOnClickListener(listner);
}
}
But to handle click in Activity
you will going to need clicked position. You can have it with adapter.getAdapterPosition()
to validate which item is clicked.
但是要处理点击,Activity
您将需要点击位置。您可以使用它adapter.getAdapterPosition()
来验证单击了哪个项目。
Apart from that if you already have reference of Activity
you can have OnClick
inside adapter and call a public method of Activity
with position to perform action.
除此之外,如果您已经有参考,Activity
您可以拥有OnClick
内部适配器并调用Activity
with position的公共方法来执行操作。
A better way to handle clicks in ViewHolder
. See the below example.
处理ViewHolder
. 请参阅以下示例。
class Holder extends RecyclerView.ViewHolder implements View.OnClickListener {
Button button;
public Holder(View itemView) {
super(itemView);
button=itemView.findViewById(R.id.b1);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v.getId()==R.id.b1){
int position=getAdapterPosition();
// Call a public method of Activity here
// with postion
}
}
}
回答by Sila Siebert
If I understood correctly you want to set the on click logic in the Activity.
如果我理解正确,您想在活动中设置点击逻辑。
You can do this by setting the OnClickListener in the Activity and passing it in the Adapter constructor.
您可以通过在 Activity 中设置 OnClickListener 并将其传递到 Adapter 构造函数来完成此操作。
MyAdapter myAdapter = new MyAdapter(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(activity, "clicked on " +position, Toast.LENGTH_SHORT).show();
}
}));
And your MyAdapter Constructor would be:
你的 MyAdapter 构造函数将是:
final private OnClickListener onClickListener;
public MyAdapter(OnClickListener onClickListener) {
this.OnClickListener = OnClickListener;
}
So your new code would be something like this
所以你的新代码会是这样的
public void onBindViewHolder(MyHolder holder, final int position) {
final Listdata data = listdata.get(position);
holder.vname.setText(data.getName());
holder.vname.setOnClickListener(onClickListener);
}
}
回答by Hussain
Create an interface for the adapter class
为适配器类创建一个接口
private OnItemClickListener mListener;
public CustomAdapter(List<Listdata> listdata, OnItemClickListener listener) {
mListener = listener;
...
...
}
private class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ViewHolder(View view) {
...
...
view.setOnClickLister(this);
}
@override
public void onClick(View v) {
mListener.onAdapterItemClick(getAdapterPosition())
}
}
interface OnItemClickListener {
void onAdapterItemClick(int position);
}
Let the activity implement the interface
让活动实现接口
public class CustomListActivity extends AppCompatActivity implements OnItemClickListener {
...
...
@override
public void onAdapterItemClick(int position) {
Toast.makeText(activity, "clicked on " +position, Toast.LENGTH_SHORT).show();
}
There is another way of doing this, check out thisimplementation
还有另一种方法可以做到这一点,请查看此实现
回答by Amir Dora
I found super duper easy method! I recommend this one
我发现了超级简单的方法!我推荐这个
Example Code:
示例代码:
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);
Picasso.with(itemView.getContext()).load(item.imageUrl).into(image);
itemView.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
listener.onItemClick(item);
}
});
}
}
}
And Use RecyclerView Adapter using below code:
并使用以下代码使用 RecyclerView Adapter:
recycler.setAdapter(new ContentAdapter(items, new ContentAdapter.OnItemClickListener() {
@Override public void onItemClick(ContentItem item) {
Toast.makeText(getContext(), "Item Clicked", Toast.LENGTH_LONG).show();
}
}));
i found this from here
我从这里找到了这个
Hope it helped you.
希望对你有帮助。
回答by Null Pointer Exception
very simple and clean solution is:
非常简单和干净的解决方案是:
create a class with the name of RecyclerTouchListener:
public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
private GestureDetector gestureDetector;
private ClickListener clickListener;
public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener 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) {
}
public interface ClickListener {
void onClick(View view, int position);
void onLongClick(View view, int position);
}
}
in your recyclerview activity:
在您的回收站活动中:
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext(), recyclerView, new RecyclerTouchListener.ClickListener() {
@Override
public void onClick(View view, int position) {
speech(countries_list_code[position]);
}
@Override
public void onLongClick(View view, int position) {
}
}));
回答by MrX
I always have one Generic Adapter in my project to avoid make a Adapter class every I use a Recyclerview. Here some example
我的项目中总是有一个通用适配器,以避免每次使用 Recyclerview 时都创建一个适配器类。这里有一些例子
public class AdapterRecyclerviewTextOnly extends RecyclerView.Adapter<AdapterRecyclerviewTextOnly.ViewHolder> {
private RecyclerView recyclerView;
private OnRecyclerviewListener onRecyclerviewListener;
public interface OnRecyclerviewListener {
void onRecyclerviewBind(RecyclerView recyclerView, AdapterRecyclerviewTextOnly.ViewHolder viewHolder, int position);
void onRecyclerviewClick(RecyclerView recyclerView, int position);
int onItemCount(RecyclerView recyclerView);
}
public void setOnRecyclerviewListener(OnRecyclerviewListener listener) { this.onRecyclerviewListener = listener; }
public AdapterRecyclerviewTextOnly(RecyclerView recyclerView) {
super();
this.recyclerView = recyclerView;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
RecyclerView recyclerView;
public TextView textView;
ViewHolder(RecyclerView recyclerView, View itemView) {
super(itemView);
this.recyclerView = recyclerView;
this.itemView.setOnClickListener(this);
this.textView = itemView.findViewById(R.id.textview_title);
}
void onBind(int position) { onRecyclerviewListener.onRecyclerviewBind(this.recyclerView, this, position); }
@Override
public void onClick(View v) {
onRecyclerviewListener.onRecyclerviewClick(this.recyclerView, getAdapterPosition());
}
}
@Override
public AdapterRecyclerviewTextOnly.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View inflatedView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recyclerview_text_only, parent, false);
return new ViewHolder(this.recyclerView, inflatedView);
}
@Override
public void onBindViewHolder(AdapterRecyclerviewTextOnly.ViewHolder holder, int position) {
holder.onBind(position);
}
@Override
public int getItemCount() {
return onRecyclerviewListener.onItemCount(this.recyclerView);
}
}
And then in your Activity Class, you can use this adapter with :
然后在您的活动类中,您可以使用此适配器:
this.recyclerView = findViewById(R.id.recyclerview);
this.recyclerView.setHasFixedSize(true);
this.recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
AdapterRecyclerviewTextOnly recyclerViewAdapter = new AdapterRecyclerviewTextOnly(this.recyclerView);
this.recyclerView.setAdapter(this.recyclerViewAdapter);
this.recyclerViewAdapter.setOnRecyclerviewListener(new AdapterRecyclerviewTextOnly.OnRecyclerviewListener() {
@Override
public void onRecyclerviewBind(RecyclerView recyclerView, AdapterRecyclerviewTextOnly.ViewHolder viewHolder, int position) {
}
@Override
public void onRecyclerviewClick(RecyclerView recyclerView, int position) {
}
@Override
public int onItemCount(RecyclerView recyclerView) {
}
});
You can reuse this with 2 or 3 recyclerview too.
First, declare a globar listener private AdapterRecyclerviewTextOnly.OnRecyclerviewListener listener;
.
您也可以使用 2 或 3 个 recyclerview 重复使用它。首先,声明一个全局侦听器private AdapterRecyclerviewTextOnly.OnRecyclerviewListener listener;
。
Then init the listener with new object then set the your every recyclerview with the listener. Use specific identifier:
然后用新对象初始化监听器,然后用监听器设置你的每一个回收器视图。使用特定标识符:
if (recyclerView == recyclerViewA){ } else if (recyclerView == recyclerViewB) { }
to manage your recyclerview inside the adapter.
if (recyclerView == recyclerViewA){ } else if (recyclerView == recyclerViewB) { }
在适配器内管理您的回收站视图。