有人使用RecyclerView找到了一种方法来设置一个onClickListener的项目在RecyclerView? 我想设置一个监听器为每个项目的布局,但这似乎有点太麻烦了 我确信有一种方法让RecyclerView监听onClick事件,但我不能完全弄清楚。


当前回答

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

            }
}){})

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

其他回答

From most of the answers above, they seem to be setting their onclicklisteners to individual items. However, the solution am about to offer is very simple but yet not intuitive to many. Many are forgetting that the other components are always in a parent component which is used to display items in the List or Recycler views. This solution is just about setting a single onclick listener to this parent view and the turn is played. The solution also includes a way to pass the position of the item being clicked on from the list or recycler view. Here, our main rootview is a CardView from the android support library. Here is sample code

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

    }
}
}

这里有一个简单明了的方法是添加到您的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()返回当前被单击项的位置

根据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
}

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

我喜欢在适配器中添加OnItemClickListener接口,当您从ViewHolder中单击项目视图时调用onClick方法。因此,管理项目点击的职责不在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);
  }

  ...
}

我们捕获项目根视图的单击,以及当回调触发时适配器上的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
            }
        });
        ...
    }
...
}

以下是我所做的。这个解决方案同时支持onClick和onLongClick在两个RecyclerView项目和视图内的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;
}

我使用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()也被调用(当点击图像)。