RecyclerView onClick

Cur*_*ees 544 android onclick onclicklistener android-recyclerview

有没有人使用RecyclerView找到一种方法来设置一个onClickListener项目RecyclerView?我想为每个项目的每个布局设置一个监听器,但这似乎有点太麻烦我确信有一种方法RecyclerView可以听取这个onClick事件,但我无法弄明白.

Jac*_*bak 589

这是一种更好,更紧密耦合的方式来实现OnClickListener一个RecyclerView.

使用片段:

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
      }
    })
);
Run Code Online (Sandbox Code Playgroud)

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){}
}
Run Code Online (Sandbox Code Playgroud)

  • 这不会提供有关单击哪个按钮或视图(项目内)的任何线索.但是对于整体项目点击,这很好. (82认同)
  • ngen的注释是正确的 - 如果要将onClick侦听器附加到项目视图中的特定项目,则应该在适配器,onBindViewHolder或viewholder本身中执行此操作. (27认同)
  • 这个解决方案感觉非常笨重,处理"点击"时有一些延迟,感觉不是很好 (19认同)
  • 这种方法的一个问题是当你做一些需要几百毫秒的事情时,比如开始一项活动.单击该项目并且单击动画时,单击和查看动画之间会有明显的延迟. (16认同)
  • 任何人都可以向我解释为什么这个使用GestureDetector的解决方案应该是一个更好的解决方案,而不仅仅是在适配器中使用onBindViewHolder()内的"setOnClickListener"到相应的元素?这样至少我需要的代码少于GestureDetector解决方案.谢谢你的解释. (6认同)
  • 我使用什么代替view.getChildPosition,因为它已被折旧? (2认同)
  • @JacobTabak为什么这个方法比在单个项目上附加onClickListener更好? (2认同)
  • 由于触摸事件与它们所代表的视图分离,因此该实现引入了一些尴尬的边缘情况.其中包括点击计时.默认情况下,GestureDetector支持长按,因此消耗的时间更长,从不报告 - 应该关闭长按.另一个是分别设置视图的可视可点击性的要求.此实现不与启用视图以向用户显示此状态相关联. (2认同)

nha*_*man 455

由于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);
}
Run Code Online (Sandbox Code Playgroud)

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();
}
Run Code Online (Sandbox Code Playgroud)

  • 你介意告诉哪些课是你的片段吗?属于`OnClickListener`的`onClick()`可以附加到任何视图.这里的整个问题是哪个!请努力,方法不仅要通过名称来识别,还要至少通过类来识别.如果您没有说您的代码将被添加到适配器,您的答案实际上没有帮助. (43认同)
  • 如果我想在其点击中删除一行该怎么办? (29认同)
  • 我比你联系的那个更喜欢这个答案.谁想写一个手势监听器并点击盒子检测来处理这个问题.谷歌 - (19认同)
  • getChildPosition(view)是不推荐使用的方法 (17认同)
  • onClick方法应该在包含RecyclerView的片段中吗?因为您在MyOnClickListener类中引用了mRecyclerView.你在哪里获得对该对象的引用? (15认同)
  • 应该在哪里写MyOnClickListener类? (9认同)
  • 我们可以改用getChildLayoutPosition(view). (8认同)
  • +1,因为你明确指出另一个作者的方法不那么紧密耦合,并将其作为你的答案的第一行_链接. (5认同)
  • 这个“onClick”方法属于哪里?你是如何在 onClick 方法中获得“mRecyclerView”的? (4认同)
  • 如何在适配器中发送`mRecyclerView`? (3认同)
  • 因为很多人问这个:如果我理解正确的话, onClick() 方法位于他用于点击侦听器的类“MyOnClickListener”内。对 mRecyclerView 的引用必须作为参数传递给构造函数等(不幸的是他没有显示)。如果我错了请纠正我! (3认同)
  • 如果适配器中有待处理的更改尚未反映到布局,则getChildAdapterPosition(view)是比getChildLayoutPosition(view)更可靠的选项,getChildLayoutPosition(view)可能不等于Item的适配器位置。 (2认同)
  • 在ViewHolder创建期间绑定click侦听器是正确的方法,因为它避免了在onBindViewHolder中执行时会发生的重复侦听器分配.但是,这里缺少的技巧是我还使用ViewHolder来保留ID(或其他一些"句柄"元数据),这些ID提供了确定被点击项目的方法.这不是通过箍计算点击项目位置的所有无意义的跳跃.所以我所做的就是在持有者ctor中绑定一个点击监听器,让持有者也捕获元信息,这些信息为底层数据提供某种指针. (2认同)
  • 我发现这绝对令人震惊,尽管如上所述这样做如此简单,但这里一些投票最高的答案提倡使用 MotionEvents 和其他各种膨胀。 (2认同)

Mar*_*ban 108

我这样做,没有不适当的类,探测器等.我们的适配器内的简单代码.特别是比以前更好的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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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);
    }
});
Run Code Online (Sandbox Code Playgroud)

  • ViewHolder必须是静态的才能获得最佳性能.这不是一个好的答案. (10认同)
  • 静态clickListener会创建内存泄漏.将侦听器声明为非静态并将其绑定到ViewHolder. (9认同)
  • @AJW最简单的方法是尽早初始化侦听器并将其作为参数传递给 Adapter 构造函数,然后传递给 ViewHolder 构造函数。 (2认同)

bol*_*lot 96

看看类似的问题 @CommonsWare的评论链接到这个,它实现了OnClickListener界面viewHolder.

这是一个简单的例子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++){

        }


      }
  }
Run Code Online (Sandbox Code Playgroud)

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);
    }
Run Code Online (Sandbox Code Playgroud)

  • @tencent我不明白这是怎么回事.如果ViewHolder本身包含有关单击元素本身时选择的数据的所有信息,那么容器的唯一责任是显示N个元素,而不是处理特定第i个元素的选择. N个元素.如果你不得不创建一个比简单行更复杂的对象列表,那么`ListView`就已经成了问题.如果根据单击ListView中的项目的位置需要处理不同的事件,该怎么办?你完蛋了.在这里,你有每个听众. (17认同)
  • 这似乎走错了方向.如果您需要在另一个片段/活动中重复使用recyclerview,则适配器/视图持有者现在定义点击的逻辑而不是包含它们的任何内容.点击应该由包含实例直接或间接处理.看起来触控听众是解决这个问题的唯一有效方法. (14认同)
  • 我同意@EpicPandaForce就此问题.在阅读了Commonsware关于处理RecyclerViews点击的书之后,我也开始回答这个问题.到目前为止,它对我来说非常有用. (2认同)
  • 不赞成使用getPosition(),而是改用getAdapterPosition()或getLayoutPosition()。 (2认同)

Eng*_*uad 93

根据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) {
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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) {
        // ...
    }
}));
Run Code Online (Sandbox Code Playgroud)

  • 你还应该覆盖```public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept){}``` (4认同)

Bub*_*vor 60

这对我有用.附上OnClickListeneronBindView.我真的不知道这是否会影响性能,但似乎只需很少的代码即可正常工作.

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();
            }
    });
}
Run Code Online (Sandbox Code Playgroud)

  • 它在我的案例中被命名为'itemView'而不是'view',只是说对于初学者,他们中的一些人不明白他们正在复制什么,并且无法弄清楚为什么不起作用 (18认同)
  • 在我的情况下holder.itemView.setOnClickListener(..) (5认同)
  • 它的布局位置 (3认同)
  • 这个解决方案对我来说似乎是最好的,但是在性能方面与@bolot的答案有何不同?他直接在ViewHolder类上实现了View.OnClickListener,然后单独吐出了onClick方法。哪个是最佳解决方案? (2认同)

Sir*_*rst 46

对于我来说,这对于活动中的项目点击侦听器来说是如此困难,并且对于不会在项目单击侦听器上触发的项目的单个视图具有单击侦听器.在使用Jacob Tabak的答案后,如果项目内没有其他触摸操作,我会尊重他对项目点击的回答.

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

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

 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();
}}
Run Code Online (Sandbox Code Playgroud)

在活动中,您需要通过传递实例来初始化适配器 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);
}
Run Code Online (Sandbox Code Playgroud)

和我的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);
}}
Run Code Online (Sandbox Code Playgroud)

  • 我在哪里可以给你钱.4个小时的搜索然后我读了你的帖子.感谢你发布这篇文章的时间. (3认同)
  • 这听起来很愚蠢但是,这有什么记忆或效率问题吗?因为每次正确绘制视图时我们都会分配点击监听器吗? (3认同)
  • 杀死应用程序性能并创建内存过度使用的好例子!在这个例子中,你只需要滚动来创建数百个无用的对象,这些对象在一瞬间将毫无用处,必须作为garbige进行访问.@NoobDogg是对的.不能在onBindView上创建ClickListeners.必须在onCreateView(或holder构造函数)中创建一次单击侦听器,并且在我们需要使用此适配器的屏幕时存在. (3认同)

Fif*_*eep 34

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

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

    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • getAdapterPosition()替代getPosition() (4认同)

Gop*_*rvi 25

我有一个很好的解决方案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);
}
Run Code Online (Sandbox Code Playgroud)

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

    }
Run Code Online (Sandbox Code Playgroud)

步骤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());
Run Code Online (Sandbox Code Playgroud)

步骤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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 这是最好的解决方案,因为我们通常需要在onItemClickListener上使用来自activity/fragment的很多属性,并且直接从viewholder调用它是没有意义的(我必须为每个适配器创建一个自定义构造函数).顺便说一句,你的代码有点夸张,我建议你把它切成最重要的部分(setOnItemClickListener). (2认同)

u2g*_*les 16

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

我在我选择的视图上标记了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;
}
Run Code Online (Sandbox Code Playgroud)

我使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

int position = recyclerView.getChildPosition((View)view.getParent());
Run Code Online (Sandbox Code Playgroud)

在我看来,这个解决方案的优势在于,当单击图像时,只调用onclick()图像侦听器,而当我将Jacob的解决方案与RecyclerView Item视图和我的内部视图解决方案相结合时,RecyclerView项目视图onclick( )也被称为(点击图像时).


Sus*_*ant 11

有更容易的方法来做到这一点.只需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>
Run Code Online (Sandbox Code Playgroud)

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

//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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Fra*_*Shi 9

你可以传递clickListenerAdapter.

在你的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);
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

然后传递给Adapter:

MainAdapter mainAdapter = new MainAdapter(this, mItemClick);
Run Code Online (Sandbox Code Playgroud)

Adapter's onCreateViewHolder:

 @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;
}
Run Code Online (Sandbox Code Playgroud)


小智 8

我为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
            }
        });
Run Code Online (Sandbox Code Playgroud)


sav*_*ion 7

您可以将OnClickListener实现到ViewHolder类

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());
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

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


Man*_*nta 7

方式太简单有效.

而不是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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

Gas*_*lén 7

根据Yigit Boyar 的说法,注册对 a 的点击的最佳方法RecyclerView是在创建 a 时定义点击,ViewHolder而不是仅仅为绑定new onClickListener的每个项目创建 aonBindViewHolder

例子:

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
}
Run Code Online (Sandbox Code Playgroud)

  • 它是 -1,它是 RecyclerView 的一部分 https://developer.android.com/reference/android/support/v7/widget/RecyclerView#NO_POSITION (2认同)

Jaw*_*poo 6

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

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

请注意,此实现还支持长按项目,以及对压缩状态的支持(这对于此问题的其他解决方案缺乏重要性).

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


Hem*_*mal 6

如果要捕获单个项目上的单击事件,则只需OnClickListenerViewHolder类中实现,然后在单个视图或整个视图上设置单击侦听器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();
            }
        }

    }
} 
Run Code Online (Sandbox Code Playgroud)


4gu*_*71n 5

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

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
    }
  ...
}
Run Code Online (Sandbox Code Playgroud)

  • getChildPosition()被断头 (3认同)

xur*_*dev 5

RecyclerView没有OnClickListener和将要实现它自己.

我喜欢OnItemClickListener在单击项目视图时调用AdapteronClick方法中添加一个接口ViewHolder.因此,管理项目点击的责任在ViewHolder和之外Adapter.活动或片段将决定做什么

向侦听器和侦听器对象添加接口.

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

  ...

  private static OnItemClickListener onItemClickListener;

  ...

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

  ...
}
Run Code Online (Sandbox Code Playgroud)

我们捕获项目的根视图的单击,并在回调被触发时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);
              }
          });
      }
  }
}
Run Code Online (Sandbox Code Playgroud)

由于我们的案例中的活动或片段,片段,我们将一个监听器分配给适配器和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
            }
        });
        ...
    }
...
}
Run Code Online (Sandbox Code Playgroud)


Muh*_*yaz 5

这就是我所做的.阅读更多信息并在此处下载要点

在这里添加相同

CustomItemClickListener.java

public interface CustomItemClickListener {
 public void onItemClick(View v, int position);
}
Run Code Online (Sandbox Code Playgroud)

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);
    }
 }
}
Run Code Online (Sandbox Code Playgroud)


ana*_*ish 5

不幸的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);
}
}
Run Code Online (Sandbox Code Playgroud)

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

 <?xml version="1.0" encoding="utf-8"?>
 <resources>
  <item name="item_click_support" type="id" />
 </resources>
Run Code Online (Sandbox Code Playgroud)

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

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

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


Ara*_*ami 5

您可以在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();
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)


Nil*_*kar 5

nhaarman 答案的Kotlin 实现:

mRecyclerView.addOnItemTouchListener(object  : RecyclerItemClickListener(this, mRecyclerView,object :RecyclerItemClickListener.OnItemClickListener{
            override fun onItemClick(view: View, position: Int) {

            }

            override fun onLongItemClick(view: View?, position: Int) {

            }
}){})
Run Code Online (Sandbox Code Playgroud)

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) {}
}
Run Code Online (Sandbox Code Playgroud)