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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 03:10:33  来源:igfitidea点击:

RecyclerView OnClickListener (Best practice way)

javaandroidandroid-recyclerviewandroid-gridview

提问by Amir Dora

I use RecyclerViewadapter to display data inside an activity, I want to implement onClickListenerinside the activity, currently, I am setting onClickListenerinside 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 onClickListenerfrom 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 onBindViewHoldermethod, 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 Activityimplements View.OnClickListenerand 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 Activityyou 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 Activityyou can have OnClickinside adapter and call a public method of Activitywith position to perform action.

除此之外,如果您已经有参考,Activity您可以拥有OnClick内部适配器并调用Activitywith 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) { }在适配器内管理您的回收站视图。