ChatGPT解决这个技术问题 Extra ChatGPT

有没有人使用 RecyclerView 找到一种方法来为 RecyclerView 中的项目设置 onClickListener?我想为每个项目的每个布局设置一个侦听器,但这似乎有点太麻烦我确定 RecyclerView 有一种方法可以侦听 onClick 事件,但我不太明白出来。

RecyclerViewDemo 我发现这个项目很棒,它使用界面来提供更多自由操作。
stackoverflow.com/a/31199564/5788247

T
Tom11

这是为 RecyclerView 实现 OnClickListener 的更好且耦合度更低的方法。

用法片段:

RecyclerView recyclerView = findViewById(R.id.recycler);
recyclerView.addOnItemTouchListener(
    new RecyclerItemClickListener(context, recyclerView ,new RecyclerItemClickListener.OnItemClickListener() {
      @Override public void onItemClick(View view, int position) {
        // do whatever
      }

      @Override public void onLongItemClick(View view, int position) {
        // do whatever
      }
    })
);

RecyclerItemClickListener 实施:

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);

    public void onLongItemClick(View view, int position);
  }

  GestureDetector mGestureDetector;

  public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
    mListener = listener;
    mGestureDetector = 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 && mListener != null) {
                mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child));
            }
        }
    });
}

  @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 true;
    }
    return false;
  }

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

  @Override
  public void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
}

这不会提供有关单击了哪个按钮或视图(在项目内)的任何线索。但是对于整体项目点击,这很好。
ngen 的评论是正确的 - 如果您想将 onClick 侦听器附加到项目视图中的特定项目,您可能应该在您的适配器、onBindViewHolder 或您的视图本身中执行此操作。
这种方法的一个问题是当你做一些需要几百毫秒的事情时,比如开始一个活动。当该项目被点击时,它有一个点击动画,点击和看到动画之间有一个明显的延迟。
这个解决方案感觉非常笨重,处理“点击”时有一些延迟,感觉不只是好的
谁能向我解释为什么这个带有 GestureDetector 的解决方案应该是一个更好的解决方案,而不是仅在适配器中的 onBindViewHolder() 中使用“setOnClickListener”到相应的元素?这样至少我需要比 GestureDetector 解决方案更少的代码。感谢您的解释。
n
nhaarman

由于 API 发生了根本性的变化,如果您要为每个项目创建一个 OnClickListener,我不会感到惊讶。不过也不是那么麻烦。在您的 RecyclerView.Adapter<MyViewHolder> 实现中,您应该:

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);
}

onClick 方法:

@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();
}

如果我想在点击时删除一行怎么办?
我比您链接的答案更喜欢这个答案。谁想写一个手势监听器和命中框检测来处理这个。谷歌 -
getChildPosition(view) 是不推荐使用的方法
你介意告诉你的片段在哪些类吗? onClick(),属于 OnClickListener 可以附加到任何视图。这里的整个问题是哪个!请努力,一个方法不仅可以通过名称来识别,而且至少可以通过一个类来识别。如果您没有说要将代码添加到适配器中,那么您的回答并没有真正的帮助。
onClick 方法是否应该在包含 RecyclerView 的片段中?因为您在 MyOnClickListener 类中引用了 mRecyclerView。您从哪里获得对该对象的引用?
B
Bakyt

我是这样做的,没有过多的类、检测器等。我们的适配器内有简单的代码。 longClick 的解决方案尤其比之前介绍的更好。

public class PasswordAdapter extends RecyclerView.Adapter<PasswordAdapter.ViewHolder> {
    private static ClickListener clickListener;

    public static 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) {
            clickListener.onItemClick(getAdapterPosition(), v);
        }

        @Override
        public boolean onLongClick(View v) {
            clickListener.onItemLongClick(getAdapterPosition(), v);
            return false;
        }
    }

    public void setOnItemClickListener(ClickListener clickListener) {
        PasswordAdapter.clickListener = clickListener;
    }

    public interface ClickListener {
        void onItemClick(int position, View v);
        void onItemLongClick(int position, View v);
    }
}

然后在片段或活动中,只需点击:

PasswordAdapter mAdapter = ...;

mAdapter.setOnItemClickListener(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);
    }
});

而不是 OurAdapter.clickListener 我认为 Marurban 意味着 PasswordAdapter.clickListener 而不是 TrainingAdapter.ClickListener(),应该是 PasswordAdapter.ClickListener()。除此之外,很棒的解决方案 Marurban!为我工作
onItemClick 侦听器也在长按时被激活。
ViewHolder 必须是静态的才能获得最佳性能。这不是一个好的答案。
静态 clickListener 会造成内存泄漏。将侦听器声明为非静态并将其绑定到 ViewHolder。
@AJW 最简单的方法是尽早初始化侦听器并将其作为参数传递给 Adapter 构造函数,然后是 ViewHolder 构造函数。
Y
Yosidroid

查看指向 this 的类似 question@CommonsWare 的评论链接,它实现了 viewHolder 中的 OnClickListener 接口。

以下是 ViewHolder 的一个简单示例:

    TextView textView;//declare global with in adapter class

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 recycler view
        if(getLayoutPosition()==0){
           //Do whatever you want here

        }else if(getLayoutPosition()==1){ 
           //Do whatever you want here         

        }else if(getLayoutPosition()==2){

        }else if(getLayoutPosition()==3){

        }else if(getLayoutPosition()==4){

        }else if(getLayoutPosition()==5){

        }

        //or you can use For loop if you have long list of items. Use its length or size of the list as 
        for(int i = 0; i<exampleList.size(); i++){

        }


      }
  }

Adapter 如下所示:

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view =LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);

        return new ViewHolder(view);
    }

不过,这似乎走错了方向。如果您需要在另一个片段/活动中重用回收视图,适配器/视图持有者现在正在定义点击的逻辑,而不是包含它们的任何内容。点击实际上应该由包含实例直接或间接处理。似乎触摸侦听器是解决此问题的唯一有效方法。
@tencent 我不明白这是怎么回事。如果 ViewHolder 本身包含有关单击元素本身时选择了哪些数据的所有信息,则容器的唯一职责是显示 N 个元素,而不是处理选择特定的第 i 个元素的 N 个元素。如果您必须创建一个包含比简单行更复杂的对象的列表,那么 ListView 已经存在问题。如果您需要根据您在 ListView 中单击项目的位置来处理不同的事件怎么办?你完蛋了。在这里,你有每个听众。
我同意@EpicPandaForce 对此的看法。在阅读了 Commonsware 的书中关于处理 RecyclerViews 中的点击的部分之后,我也开始支持这个答案。到目前为止,它对我来说效果很好。
findViewById 仅用于此处的视图持有者创建(因此 onCreateViewHolder)。视图持有者旨在防止每次将项目绑定到持有者时找到视图,而不是在初始创建时。
getPosition() 已弃用,请改用 getAdapterPosition()getLayoutPosition()
B
Benoit Duffez

根据 Jacob Tabak 的回答(为他 +1),我能够添加 onLongClick 监听器:

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 {
    public interface OnItemClickListener {
        void onItemClick(View view, int position);

        void onItemLongClick(View view, int position);
    }

    private OnItemClickListener mListener;

    private GestureDetector mGestureDetector;

    public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
        mListener = listener;

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

            @Override
            public void onLongPress(MotionEvent e) {
                View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());

                if (childView != null && mListener != null) {
                    mListener.onItemLongClick(childView, recyclerView.getChildAdapterPosition(childView));
                }
            }
        });
    }

    @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) {
    }
}

然后你可以像这样使用它:

recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), recyclerView, new RecyclerItemClickListener.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
        // ...
    }

    @Override
    public void onItemLongClick(View view, int position) {
        // ...
    }
}));

我花了一段时间来适应我的应用程序,并根据 Java/Android 标准调整和格式化代码,但最终它运行良好。
如何为长按添加动画?
@Eng.Fouad 点击效果不能通过使用这个来工作,尽管如果我们在适配器点击效果中设置点击监听器可以解决这个问题
您还应该覆盖 public void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
由于某种原因,它不会返回单击的视图。就我而言,我单击了一个复选框,但给定的视图有所不同。我检查的方式:view.getId() == R.id.selection
A
Andrew T.

这对我有用。将 OnClickListener 附加到 onBindView。我真的不知道这是否会影响性能,但它似乎用很少的代码就可以正常工作。

public void onBindViewHolder(ViewHolder holder, final int position) {
    holder.view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context, "Recycle Click" + position, Toast.LENGTH_SHORT).show();
            }
    });
}

在我的情况下 holder.itemView.setOnClickListener(..)
在我的情况下,它被命名为“itemView”而不是“view”,只是对初学者说,他们中的一些人不明白他们在复制什么,并且无法弄清楚为什么不起作用
它的布局位置
对我来说,这似乎只适用于最后一个可见的项目而不是点击的项目
这个解决方案对我来说似乎是最好的,但这与@bolot 在性能方面的回答有何不同?他直接在 ViewHolder 类上实现了 View.OnClickListener,而不是单独吐出 onClick 方法。哪个是最好的解决方案?
S
Sir NIkolay Cesar The First

这对我来说很难在活动中拥有项目单击侦听器,也很难为不会在项目单击侦听器上触发的项目的单个视图设置单击侦听器。在玩了 Jacob Tabak 的回答之后,如果项目内没有其他触摸动作,我尊重他对项目点击的回答。

我有一个自定义的 OnClickListener 界面,它有一个项目点击事件,它保存点击项目的视图和来自适配器的项目位置。我在构造函数中呈现它的一个实例(或者它可以使用 setter)并将它附加到视图持有者容器单击侦听器。

我在适配器中还有其他点击监听器(可以在视图持有者中),它将处理来自容器的当前视图点击。

 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();
}}

在活动中,您需要通过传递 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);
}

还有我的 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);
}}

这种方法对我来说效果很好 - 这意味着您可以在活动中而不是在网格视图中处理点击
我在哪里可以给你钱。 4小时的搜索,然后我读了你的帖子。感谢您花时间发布此内容。
这听起来很愚蠢,但是,这是否有任何内存或效率之类的问题?因为每次绘制视图时我们都在分配点击侦听器,对吗?
@Raghav 是的,每次绑定视图时都会分配一个新的单击侦听器,但这是标准流程。但是 mOnItemClickListener 只为适配器创建一次,只是视图及其位置在每个项目单击时都不同;)
杀死应用程序性能并造成内存过度使用的好例子!在这个例子中,你只需要滚动来创建数百个无用的对象,这些对象很快就会变得无用并且必须作为垃圾访问。 @NoobDogg 是对的。在 onBindView 上不需要创建任何 ClickListener。必须在 onCreateView (或持有者构造函数)中创建一次单击侦听器,并且在我们需要带有此适配器的屏幕时存在。
F
Fifer Sheep

这就是我最终需要的,以防有人发现它有用:

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());
            }
        });

    }
}

来源:http://blog.csdn.net/jwzhangjie/article/details/36868515


在我尝试过的所有版本中,这是我正在使用的版本。但是这样可以吗?还是有更好的方法,比如最佳实践?
据我所知,这是唯一的方法。查看此内容以获取更多详细信息! stackoverflow.com/a/24933117/1508887
如何从 onclick 方法中打开新片段?
getAdapterPosition() 替换 getPosition()
getAdapterPosition() 已弃用:“当适配器嵌套其他适配器时,此方法会令人困惑。如果您在适配器的上下文中调用它,您可能想要调用 getBindingAdapterPosition() 或者如果您想要 RecyclerView 看到的位置,您应该调用 getAbsoluteAdapterPosition()"
G
Gopal Singh Sirvi

我对项目和子项目的 RecyclerViewonItemClickListener 有很好的解决方案

第 1 步 - 创建接口

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- 然后在适配器的onBindViewHolder方法中使用如下方式

/**
     * 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);
        }
    
    }

第 3 步 - 在您使用它的活动或片段中查找并设置回收站视图

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());

第 4 步 - 最后在您使用 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();
        }
    }

Kotlin 语言的更新我已经更新了 kotlin 的代码,其中只有整个视图具有点击侦听器。您可以根据上面的java代码通过编辑界面和代码来设置子项点击监听器。

适配器

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)
    }
}

活动或片段

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)
            }

        })

这是最好的解决方案,因为我们通常需要我们的 onItemClickListener 上的活动/片段的许多属性,并且直接从视图持有者调用它是没有意义的(我必须为每个适配器创建一个自定义构造函数)。顺便说一句,你的代码有点冗长,我建议你把它剪到最重要的部分(setOnItemClickListener)。
这是区分行/项目与子项目的好方法
我听说这是不好的解决方案,因为您创建了太多听众。
它将创建与屏幕上可见的项目一样多的侦听器。当我们滚动时,未使用的侦听器将被垃圾收集
另一种方法是在视图中添加一个标签,我们可以使用位置编号作为标签并只创建一个监听器并将其设置为所有项目。然后通过获取标签来找出位置
u
u2gilles

这就是我所做的。此解决方案同时支持 RecyclerView 项目和 RecyclerView 项目内部的视图(内部视图)的 onClick 和 onLongClick。

我在我选择的观点上标记 viewHolder :

public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item, null);
    ViewHolder viewHolder = new ViewHolder(itemView);

    itemView.setOnClickListener( this);
    itemView.setOnLongClickListener(this);
    viewHolder.imageIV.setOnClickListener(this);
    viewHolder.imageIV.setOnLongClickListener(this);

    viewHolder.imageIV.setTag(viewHolder);
    itemView.setTag(viewHolder);

    return viewHolder;
}

我使用 holder.getPosition() 来检索 onClick() 方法中的位置(onLongClick 类似):

public void onClick(View view) {
    ViewHolder holder = (ViewHolder) view.getTag();
    int position = holder.getPosition();

    if (view.getId() == holder.imageIV.getId()){
        Toast.makeText(context, "imageIV onClick at" + position, Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(context, "RecyclerView Item onClick at " + position, Toast.LENGTH_SHORT).show();
    }
}

带有 getChildPosition 的变体也可以。请注意,对于内部视图,在 onClick() 中使用:

int position = recyclerView.getChildPosition((View)view.getParent());

在我看来,此解决方案的优势在于,当单击图像时,仅调用 onclick() 图像侦听器,而当我将 Jacob 的 RecyclerView 项目视图解决方案和我的内部视图解决方案结合起来时,RecyclerView 项目视图 onclick( ) 也称为(单击图像时)。


还有一些其他方法可以使用 ViewHolder:1 - ViewGroup rowView = (ViewGroup)viewHolder.imageIV.getParent() 来获取对完整列表行 View 的引用。 2 - View rowView = viewHolder.itemView。然后您可以将 onClickListeners 添加到这些 rowViews
S
Sushant

有更简单的方法可以做到这一点。只需在根视图的 onBindViewHolder 中单击即可应用。

考虑这是您对适配器的看法,

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/linearlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

        <TextView
            android:id="@+id/textview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="1dp"
            android:textSize="15sp" />
</LinearLayout>

然后在您的适配器中执行以下操作

//get the layout and make view holder
@Override
public RVAdapter.ViewHolder1 onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_layout, null);
    ViewHolder1 viewHolder = new ViewHolder1(view);
    return viewHolder;
}

@Override
public void onBindViewHolder(RVAdapter.ViewHolder1 holder, int position) {

    //apply on click on your root view
    holder.linearlayout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //Do on click stuff
        }
    });
}

//make references to views in layout including root view
public class ViewHolder1 extends RecyclerView.ViewHolder {

    protected LinearLayout linearlayout = null
    protected TextView textview = null;

    public CareerLinksViewHolder(View itemView) {
        super(itemView);

        this.linearlayout = (LinearLayout) itemView.findViewById(R.id.linearlayout);
        this.tvCompName = (TextView) itemView.findViewById(R.id.textview);
    }
}

T
Tom11

方式太简单和有效。

而不是在视图持有者内实现接口 View.OnClickListener 或在您的活动中创建接口和实现接口 - 我使用此代码进行简单的 OnClickListener 实现。

public static class SimpleStringRecyclerViewAdapter
            extends RecyclerView.Adapter<SimpleStringRecyclerViewAdapter.ViewHolder> {

        // Your initializations goes here...
        private List<String> mValues;

        public static class ViewHolder extends RecyclerView.ViewHolder {

            //create a variable mView
            public final View mView;

            /*All your row widgets goes here
            public final ImageView mImageView;
            public final TextView mTextView;*/

            public ViewHolder(View view) {
                super(view);
                //Initialize it here
                mView = view;

                /* your row widgets initializations goes here
                mImageView = (ImageView) view.findViewById(R.id.avatar);
                mTextView = (TextView) view.findViewById(android.R.id.text1);*/
            }
        }

        public String getValueAt(int position) {
            return mValues.get(position);
        }

        public SimpleStringRecyclerViewAdapter(Context context, List<String> items) {

            mBackground = mTypedValue.resourceId;
            mValues = items;
        }

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

        @Override
        public void onBindViewHolder(final ViewHolder holder, int position) {
            holder.mBoundString = mValues.get(position);
            holder.mTextView.setText(mValues.get(position));

            //Here it is simply write onItemClick listener here
            holder.mView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Context context = v.getContext();
                    Intent intent = new Intent(context, ExampleActivity.class);

                    context.startActivity(intent);
                }
            });
        }

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

这是一种常见的不良做法,因为它看起来太容易了。每次绑定对象时,您都在创建一个新的内部侦听器(并且回收器中的每个项目都可以绑定很多次),这对 a) 性能 b) 垃圾收集不利。相反,您应该在某处(在视图支架中、在适配器中、在上部片段或活动中)创建一个侦听器,然后将其添加到 onCreateViewHolder 中的视图支架构造函数中的项目中。这增加了必须确定哪个项目是点击器的复杂性,但可以通过标签或向持有者添加更多信息轻松解决。
T
Tom11

您可以将 clickListener 传递给 Adapter

在您的 Activity 中:

private View.OnClickListener mItemClick = new View.OnClickListener() {

    @Override
    public void onClick(View v) {
        Intent intent = null;
        int position = list.getChildPosition(v);
        switch (position) {
            case 0:
                intent = new Intent(MainActivity.this, LeakCanaryActivity.class);
                break;
            case 1:
                intent = new Intent(MainActivity.this, ButterKnifeFragmentActivity.class);
                break;
        }
        if (intent != null) {
            MainActivity.this.startActivity(intent);
        }
    }
};

然后将其传递给 Adapter

MainAdapter mainAdapter = new MainAdapter(this, mItemClick);

AdapteronCreateViewHolder 中:

 @Override
public MainAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
    View itemView = activity.getLayoutInflater().inflate(R.layout.main_adapter_item, viewGroup, false);
    ViewHolder holder = new ViewHolder(itemView);
    itemView.setOnClickListener(mItemClick);
    return holder;
}

您如何通过意图传递 holder 值?
s
savepopulation

您可以在 ViewHolder 类中实现 OnClickListener

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());
        }
    }

并且 onBindViewHolder 设置您的视图持有者的项目

public void onBindViewHolder(ViewHolder holder, int position) {
        holder.tvTitle.setText(objects.get(position).getTitle());
        holder.item = objects.get(position);
        }

A
Abdullah

如果您想在单个项目上捕获点击事件,那么只需在 ViewHolder 类中实现 OnClickListener,然后在单个视图或整个 itemView 上设置点击侦听器。

以下示例显示相同

public  class ContactViewHolder extends RecyclerView.ViewHolder implements OnClickListener
    {
        TextView txt_title,txt_name,txt_email;

        public ContactViewHolder(View itemView) 
        {
            super(itemView);
            txt_title = (TextView)itemView.findViewById(R.id.txt_title);
            txt_name  = (TextView)itemView.findViewById(R.id.txt_name);
            txt_email = (TextView)itemView.findViewById(R.id.txt_email);

            txt_name.setOnClickListener(this);
            txt_email.setOnClickListener(this);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub

            if(v == itemView)
            {
                Toast.makeText(RecyclerDemoActivity.this, "Visiting Card Clicked is ==>"+txt_name.getText(), Toast.LENGTH_SHORT).show();
            }

            if(v == txt_name)
            {
                Toast.makeText(RecyclerDemoActivity.this, "Name ==>"+txt_name.getText(), Toast.LENGTH_SHORT).show();
            }

            if(v == txt_email)
            {
                Toast.makeText(RecyclerDemoActivity.this, "Email ==>"+txt_email.getText(), Toast.LENGTH_SHORT).show();
            }
        }

    }
} 

C
Chathura Jayanath

我已经为 android 开发了一个轻量级库,您可以访问 https://github.com/ChathuraHettiarachchi/RecycleClick

并遵循以下示例

RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
            @Override
            public void onItemClicked(RecyclerView recyclerView, int position, View v) {
                // YOUR CODE
            }
        });

可以确认,这个库很棒!非常容易使用,干得好!
G
Gastón Saillén

根据 Yigit Boyar,在 RecyclerView 上注册点击的最佳方式是在创建 viewholder 时定义点击,而不是仅仅为 onBindViewHolder 绑定的每个项目创建一个新的 onClickListener

例子

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
}

没有立场是什么?
它是 -1,它是 RecyclerView developer.android.com/reference/android/support/v7/widget/… 的一部分
J
Jawnnypoo

到目前为止发布的所有答案都是很好的解决方案,但是如果您不想处理太多的实现细节,只是希望它与 ListView 的工作方式类似,我建议使用 TwoWay-View,如下所示:

https://github.com/lucasr/twoway-view

请注意,此实现还支持对项目的长按,以及对按下状态的支持(这是该问题的其他解决方案所缺乏的重要内容)。

如果您不想使用整个库,请查看 ClickItemTouchListener 类,如果需要,它可以用作独立的。我目前发现的唯一问题是长按+滚动,它似乎有不正确的行为。


4
4gus71n

对我来说,这是最好的方法:

class YourRecyclerAdapter extends RecyclerView.Adapter<ContactViewHolder> implements View.OnClickListener { 
  ...
  @Override
  public void onClick(View view) {
        int itemPosition = vRecycle.getChildPosition(view);
        //And use itemPosition to get the item from your collection. This way you dont restrain the ViewHolder with a OnClick callback
    }
  ...
}

getChildPosition() 被斩首
T
Tom11

RecyclerView 没有 OnClickListener,必须自己实现。

我喜欢在 Adapter 中添加一个 OnItemClickListener 界面,并在您单击 ViewHolder 中的项目视图时调用 onClick 方法。因此,管理对项目的点击的责任不在 ViewHolderAdapter 范围内。将决定做什么的活动或片段

向监听器和监听器对象添加接口。

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

  ...

  private static OnItemClickListener onItemClickListener;

  ...

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

  ...
}

我们捕获项目的根视图的单击以及触发回调时的 onClick 适配器上的侦听器调用。

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

  ...

  private static OnItemClickListener onItemClickListener;

  ...

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

  ...

  public static class ViewHolder extends RecyclerView.ViewHolder {
      public ImageView imageView;

      public ViewHolder(View itemRootView) {
          super(itemRootView);
          imageView = (ImageView) itemRootView.findViewById(R.id.itemImage);

          itemRootView.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                  int position  = ViewHolder.super.getAdapterPosition();
                  onItemClickListener.onItemClick(view,position);
              }
          });
      }
  }
}

由于活动或片段,在我们的例子中,我们为适配器分配了一个监听器,onClick回调我们将按位置获取所选项目并打开项目的详细活动。

public class ItemsFragment extends Fragment {
    ...
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
       ...    
        ((ItemsAdapter) adapter).setOnItemClickListener(new ItemsAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                //Do something when an item has been clicked
            }
        });
        ...
    }
...
}

getAdapterPosition() 已弃用:“当适配器嵌套其他适配器时,此方法令人困惑。如果您在适配器的上下文中调用它,您可能想要调用 getBindingAdapterPosition() 或者如果您想要 RecyclerView 看到的位置,您应该调用 getAbsoluteAdapterPosition()"
T
Tom11

不幸的是,RecyclerView 缺少 ListView 的一些内置功能。例如,添加在单击项目时触发的 OnItemClickListener 的能力。 RecyclerView 允许您在适配器中设置一个 OnClickListener,但是将该点击侦听器从您的调用代码传递到适配器和 ViewHolder,对于捕获简单的项目点击来说是很复杂的。

public class ItemClickSupport {
private final RecyclerView mRecyclerView;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (mOnItemClickListener != null) {
            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
            mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
        }
    }
};
private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        if (mOnItemLongClickListener != null) {
            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
            return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
        }
        return false;
    }
};
private RecyclerView.OnChildAttachStateChangeListener mAttachListener
        = new RecyclerView.OnChildAttachStateChangeListener() {
    @Override
    public void onChildViewAttachedToWindow(View view) {
        if (mOnItemClickListener != null) {
            view.setOnClickListener(mOnClickListener);
        }
        if (mOnItemLongClickListener != null) {
            view.setOnLongClickListener(mOnLongClickListener);
        }
    }

    @Override
    public void onChildViewDetachedFromWindow(View view) {

    }
};

private ItemClickSupport(RecyclerView recyclerView) {
    mRecyclerView = recyclerView;
    mRecyclerView.setTag(R.id.item_click_support, this);
    mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
}

public static ItemClickSupport addTo(RecyclerView view) {
    ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
    if (support == null) {
        support = new ItemClickSupport(view);
    }
    return support;
}

public static ItemClickSupport removeFrom(RecyclerView view) {
    ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
    if (support != null) {
        support.detach(view);
    }
    return support;
}

public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
    mOnItemClickListener = listener;
    return this;
}

public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
    mOnItemLongClickListener = listener;
    return this;
}

private void detach(RecyclerView view) {
    view.removeOnChildAttachStateChangeListener(mAttachListener);
    view.setTag(R.id.item_click_support, null);
}

public interface OnItemClickListener {

    void onItemClicked(RecyclerView recyclerView, int position, View v);
}

public interface OnItemLongClickListener {

    boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
}
}

您还需要使用 ids.xml 定义 R.id.item_click_support

 <?xml version="1.0" encoding="utf-8"?>
 <resources>
  <item name="item_click_support" type="id" />
 </resources>

生成的代码点击监听器现在看起来像这样:

ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
    // do it
}
});

有关 recyclerview 点击的简要说明,请查看此littlerobots_blog


getAdapterPosition() 已弃用:“当适配器嵌套其他适配器时,此方法令人困惑。如果您在适配器的上下文中调用它,您可能想要调用 getBindingAdapterPosition() 或者如果您想要 RecyclerView 看到的位置,您应该调用 getAbsoluteAdapterPosition()"
A
Arash Hatami

您可以在 ViewHolder 类中轻松定义 setOnClickListener ,如下所示:

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();
            }
        });
    }
}

N
Nilesh Deokar

nhaarman's answer 的 Kotlin 实现:

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) {}
}

谢谢,这甚至比最初的答案更好。对我来说很好
M
MyNT

这是我所做的Read more & download the gist 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);
    }
 }
}

getAdapterPosition() 已弃用:“当适配器嵌套其他适配器时,此方法令人困惑。如果您在适配器的上下文中调用它,您可能想要调用 getBindingAdapterPosition() 或者如果您想要 RecyclerView 看到的位置,您应该调用 getAbsoluteAdapterPosition()"
A
Akah

从上面的大多数答案中,他们似乎将 onclicklisteners 设置为单个项目。然而,即将提供的解决方案非常简单,但对许多人来说并不直观。许多人忘记了其他组件始终位于父组件中,该父组件用于在 List 或 Recycler 视图中显示项目。该解决方案只是为此父视图设置一个 onclick 侦听器并播放轮次。该解决方案还包括一种从列表或回收站视图传递被单击项目的位置的方法。在这里,我们的主要根视图是来自 android 支持库的 CardView。这是示例代码

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

public static final String LOG_TAG = ListAdapter.class.getSimpleName();
private Cursor mDataset;
private Context mContext;
private ViewHolder mViewHolder;

// Provide a suitable constructor (depends on the kind of dataset)
public ListAdapter(Context context, Cursor Dataset) {
    mDataset = Dataset;
    mContext = context;
}

// Create new views (invoked by the layout manager)
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    // create a new view
    View v = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.list_business_view, parent, false);

    mViewHolder = new ViewHolder(v);
    return mViewHolder;
}

public void setData(Cursor newdata) {
    this.mDataset = newdata;
}

// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
//Bind data to other items here. To save time, i have ommited that.
           //here is where we attach a click listerner for an item in the recycler list rather than for each element of a given item.
            holder.card.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(mContext, " Just cliked item at position " + itemPosition, Toast.LENGTH_LONG).show();

            }
        });

    }
}

// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
    if (null != mDataset) {
        return mDataset.getCount();
    }
    return 0;

}


// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder{
    // each data item is just a string in this case
    public final TextView mBusinesssName; // View for the business name
    public final TextView mBusinessCategory; //View for the category name
    public final ImageView businessImage; // View for the business category image Image
    public final TextView mBusinessDistance; // View for the distance
    public final CardView card;

    public ViewHolder(View view) {
        super(view);
        mBusinesssName = (TextView) view.findViewById(R.id.list_item_name_textview);
        mBusinessCategory = (TextView) view.findViewById(R.id.list_item_category_textview);
        mBusinessDistance = (TextView) view.findViewById(R.id.list_item_dist_textview);
        businessImage = (ImageView) view.findViewById(R.id.list_item_icon);
        card = (CardView) view.findViewById(R.id.card_view);

    }
}
}

V
Vipul Prajapati

这是在您的 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() 是返回当前点击项的位置


getAdapterPosition() 已弃用:“当适配器嵌套其他适配器时,此方法会令人困惑。如果您在适配器的上下文中调用它,您可能想要调用 getBindingAdapterPosition() 或者如果您想要 RecyclerView 看到的位置,您应该调用 getAbsoluteAdapterPosition()"
C
Community

我知道有很多答案,但我想我也可以提供我的实现。 (可在 another question I answered 上找到完整的详细信息)。

因此,要添加点击侦听器,您的内部 ViewHolder 类需要实现 View.OnClickListener。这是因为您将为 ViewHolder 的构造函数的 itemView 参数设置一个 OnClickListener。让我告诉你我的意思:

public class ExampleClickViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    TextView text1, text2;

    ExampleClickViewHolder(View itemView) {
        super(itemView);

        // we do this because we want to check when an item has been clicked:
        itemView.setOnClickListener(this);

        // now, like before, we assign our View variables
        title = (TextView) itemView.findViewById(R.id.text1);
        subtitle = (TextView) itemView.findViewById(R.id.text2);
    }

    @Override
    public void onClick(View v) {
        // The user may not set a click listener for list items, in which case our listener
        // will be null, so we need to check for this
        if (mOnEntryClickListener != null) {
            mOnEntryClickListener.onEntryClick(v, getLayoutPosition());
        }
    }
}

您需要添加的唯一其他内容是 Adapter 的自定义界面和 setter 方法:

private OnEntryClickListener mOnEntryClickListener;

public interface OnEntryClickListener {
    void onEntryClick(View view, int position);
}

public void setOnEntryClickListener(OnEntryClickListener onEntryClickListener) {
    mOnEntryClickListener = onEntryClickListener;
}

这样,您的新的支持点击的 Adapter 就完成了。

现在,让我们使用它...

    ExampleClickAdapter clickAdapter = new ExampleClickAdapter(yourObjects);
    clickAdapter.setOnEntryClickListener(new ExampleClickAdapter.OnEntryClickListener() {
        @Override
        public void onEntryClick(View view, int position) {
            // stuff that will happen when a list item is clicked
        }
    });

这基本上是您设置普通 Adapter 的方式,不同之处在于您使用您创建的 setter 方法来控制当您的用户单击特定列表项时您将执行的操作。

您还可以查看我在 GitHub 上的 Gist 上制作的一组示例:

https://gist.github.com/FarbodSalamat-Zadeh/7646564f48ee708c1582c013e1de4f07


您应该使用 getAdapterPosition() 而不是 getLayoutPosition()
N
Null Pointer Exception
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();
                }
            });
        }
    }

getAdapterPosition() 已弃用:“当适配器嵌套其他适配器时,此方法会令人困惑。如果您在适配器的上下文中调用它,您可能想要调用 getBindingAdapterPosition() 或者如果您想要 RecyclerView 看到的位置,您应该调用 getAbsoluteAdapterPosition()"
K
Karthikeyan

这是我的自定义适配器的完整代码此代码将使用名为“list_item”的 xml 文件中定义的列表项对行进行膨胀,它还将对具有相应位置的所有列表项行执行单击事件。

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;
    }
}

c
ccpizza

不要重新发明轮子!此特定用例的代码包含在 Android Studio 附带的 Master/Detail Flow 入门项目中。

从 Android Studio 中选择:

文件 > 新建 > 新建项目...。在手机和平板电脑选项卡中,选择主/详细流程,如下所示。

https://i.stack.imgur.com/TIyDl.png

将项目创建为 Kotlin 或 Java。利润。

我不会在此处包含来自 google 的 ootb 演示项目的代码,但我将概述 google 提供的示例中的主要设计方法:

OnClickListener 项仅创建一次,并分配给您的 RecyclerView.Adapter 实现中的字段。

在 onBindViewHolder() 中,您应该使用 holder.itemView.setOnClickListener(mOnClickListener) 在 ViewHolder 实例上设置相同的预先创建的 onClickListener 对象(避免在每个方法调用上创建一个新实例!);如果您需要捕获对 ViewHolder 中某些特定元素的点击,然后扩展 ViewHolder 并将您需要的元素公开为字段,以便您可以在 onBindViewHolder() 中附加您需要的任何侦听器 - 再一次,不要重新创建侦听器每个方法调用——将它们初始化为实例字段并根据需要附加它们。

您可以使用 .setTag() 将状态传递给您的 viewHolder,例如 holder.itemView.setTag(mValues.get(position));在演示中使用。


这很棒。感谢您引起我的注意 - 我通常相信大多数直接来自 Google 的做法。您知道在使用 MVVM 架构时该方法是否有任何不同?此外,在创建新项目时,它现在似乎被称为 Primary/Detail Flow!
我试了一下,它似乎不会对我的 MVVM 架构应用程序造成任何问题。我使用 ItemViewModel 作为项目视图的 .tag 对象。不确定这是否是最佳做法,但目前对我有用。