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


当前回答

太简单和有效了。

而不是实现接口视图。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();
        }
    }

其他回答

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

这是我的自定义适配器的完整代码,这段代码将用XML文件“list_item”中定义的列表项膨胀行,它还将在具有各自位置的所有列表项行上执行单击事件。

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

这里有一个策略,它给出了一个类似于ListView实现的结果,因为你可以在活动或片段级别而不是适配器或ViewHolder级别定义侦听器。它还定义了一些抽象类,这些抽象类负责适配器和持有者的大量样板工作。

抽象类

首先,定义一个抽象Holder,它扩展了RecyclerView。并定义了一个泛型数据类型T,用于将数据绑定到视图。bindViews方法将由一个子类实现,用于将数据映射到视图。

public abstract class Holder<T> extends RecyclerView.ViewHolder {
    T data;

    public Holder(View itemView) {
        super(itemView);
    }

    public void bindData(T data){
        this.data = data;
        bindViews(data);
    }

    abstract protected void bindViews(T data);
}

同样,创建一个抽象适配器,扩展RecyclerView.Adapter<Holder<T>>。这定义了3个接口方法中的2个,子类将需要实现最后一个onViewHolderCreated方法。

public abstract class Adapter<T> extends RecyclerView.Adapter<Holder<T>> {
    List<T> list = new ArrayList<>();

    @Override
    public void onBindViewHolder(Holder<T> holder, int position) {
        holder.bindData(list.get(position));
    }

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

    public T getItem(int adapterPosition){
        return list.get(adapterPosition);
    }
}

具体类

现在创建一个扩展Holder的新具体类。该方法只需定义视图并处理绑定。这里我使用ButterKnife库,但请随意使用itemView.findViewById(…)方法代替。

public class PersonHolder extends Holder<Person>{
    @Bind(R.id.firstname) TextView firstname;
    @Bind(R.id.lastname) TextView lastname;

    public PersonHolder(View view){
        super(view);
        ButterKnife.bind(this, view);
    }

    @Override
    protected void bindViews(Person person) {
        firstname.setText(person.firstname);
        lastname.setText(person.lastname);
    }
}

最后,在持有RecyclerView的Activity或Fragment类中,你会有这样的代码:

// Create adapter, this happens in parent Activity or Fragment of RecyclerView
adapter = new Adapter<Person>(){
    @Override
    public PersonHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.layout_person_view, parent, false);

        PersonHolder holder = new PersonHolder(v);
        v.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v) {
                int itemPos = holder.getAdapterPosition();
                Person person = getItem(itemPos);

                // do something with person
                EventBus.getDefault().postSticky(new PersonClickedEvent(itemPos, person));
            }
        });

        return holder;
    }
};

我们可以使用Java弱引用来实现这一点。 从语义上讲,视图持有者应该响应click事件或将其委托给正确的响应器。

我们的目标:

Viewholder应该对响应事件的类一无所知,除非它实现了某个接口。 点击处理程序应该得到被点击的视图在RecyclerView中的位置。 我们应该能够辨别视图持有人中单击了哪个视图。 保持所有组件之间的松散耦合,不要造成任何保留周期。

步骤:

Create an interface to handle click responses. Implement this interface in the Activity that will handle the click. Add a member variable in the RecyclerView Adapter to hold the Weak Reference and a constructor that sets it. Do the same in the RecyclerView ViewHolder and add a member variable to keep track of position. Set your on click listeners on any view you'd like in the ViewHolder, then callback to the responder to handle them. Change your onBindViewHolder method to set the position when binding. Pass the responder down to the ViewHolder. In the responder, you can now use getId() on the view to figure out which view was clicked.

这里是一个要点,这样你就可以看到它们是如何组合在一起的: RecyclerView点击处理

在Kotlin中也是如此

inner class MyViewHolder(v: View, myOnClickListener: MyOnClickListener) : RecyclerView.ViewHolder(v) {
    init {
        v.setOnClickListener { v -> myOnClickListener.onClick(v, adapterPosition) }
    }
}

override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): MyViewHolder {
    val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.myview, viewGroup, false)
    return MyViewHolder(view, mOnClickListener)
}

inner class MyOnClickListener {
    fun onClick(view: View, position: Int) {
        val item = mList[position]
        Toast.makeText(view.context, item, Toast.LENGTH_LONG).show()
    }
}