为什么RecyclerView没有onItemClickListener()?

Tar*_*ney 940 java android android-recyclerview

我正在探索RecyclerView,我很惊讶地看到RecyclerView它没有onItemClickListener().因为RecyclerView延伸

android.view.ViewGroup

ListView扩展

android.widget.AbsListView

.不过,我解决我的问题写onClick在我的RecyclerView.Adapter:

public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {

    public TextView txtViewTitle;
    public ImageView imgViewIcon;

    public ViewHolder(View itemLayoutView) {
        super(itemLayoutView);
        txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
        imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
    }

    @Override
    public void onClick(View v) {

    }
}
Run Code Online (Sandbox Code Playgroud)

但我仍然想知道为什么谷歌被删除了onItemClickListener()

是否有性能问题或其他问题?

MLP*_*CiM 1200

tl; dr 2016使用RxJava和PublishSubject公开点击的Observable.

public class ReactiveAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    String[] mDataset = { "Data", "In", "Adapter" };

    private final PublishSubject<String> onClickSubject = PublishSubject.create();

    @Override 
    public void onBindViewHolder(final ViewHolder holder, int position) {
        final String element = mDataset[position];

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               onClickSubject.onNext(element);
            }
        });
    }

    public Observable<String> getPositionClicks(){
        return onClickSubject.asObservable();
    }
}
Run Code Online (Sandbox Code Playgroud)

原帖:

自推出以来ListView,onItemClickListener一直存在问题.当你有任何内部元素的点击监听器时,不会触发回调但是没有通知或记录良好(如果有的话),所以存在很多混淆和SO问题.

鉴于RecyclerView它更进一步,并没有行/列的概念,而是任意布局的子项数量,他们已经将onClick委托给它们中的每一个,或者程序员实现.

可以认为Recyclerview不是ListView1:1的替代品,而是复杂用例的更灵活的组件.正如你所说,你的解决方案是谷歌对你的期望.现在你有一个适配器谁可以委托的onClick对构造函数,这是两者的正确的方式传递的接口ListViewRecyclerview.

public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {

    public TextView txtViewTitle;
    public ImageView imgViewIcon;
    public IMyViewHolderClicks mListener;

    public ViewHolder(View itemLayoutView, IMyViewHolderClicks listener) {
        super(itemLayoutView);
        mListener = listener;
        txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
        imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
        imgViewIcon.setOnClickListener(this);
        itemLayoutView.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (v instanceof ImageView){
           mListener.onTomato((ImageView)v);
        } else {
           mListener.onPotato(v);
        }
    }

    public static interface IMyViewHolderClicks {
        public void onPotato(View caller);
        public void onTomato(ImageView callerImage);
    }

}
Run Code Online (Sandbox Code Playgroud)

然后在你的适配器上

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

   String[] mDataset = { "Data" };

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

       MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() { 
           public void onPotato(View caller) { Log.d("VEGETABLES", "Poh-tah-tos"); };
           public void onTomato(ImageView callerImage) { Log.d("VEGETABLES", "To-m8-tohs"); }
        });
        return vh;
    }

    // Replace the contents of a view (invoked by the layout manager) 
    @Override 
    public void onBindViewHolder(ViewHolder holder, int position) {
        // Get element from your dataset at this position 
        // Replace the contents of the view with that element 
        // Clear the ones that won't be used
        holder.txtViewTitle.setText(mDataset[position]);
    } 

    // Return the size of your dataset (invoked by the layout manager) 
    @Override 
    public int getItemCount() { 
        return mDataset.length;
    } 
  ...
Run Code Online (Sandbox Code Playgroud)

现在看看最后一段代码:onCreateViewHolder(ViewGroup parent, int viewType)签名已经提出了不同的视图类型.对于它们中的每一个,您也需要不同的视图持有者,并且随后每个视图持有者可以具有不同的点击集.或者,您可以创建一个通用视图,它可以获取任何视图和一个视图并onClickListener相应地应用.或者将一个级别委派给协调器,以便多个片段/活动具有相同的列表,具有不同的单击行为.同样,所有的灵活性都在你身边.

它是一个非常需要的组件,与我们ListView迄今为止的内部实现和改进非常接近.谷歌最终承认这一点很好.

  • RecyclerView.ViewHolder有一个getPosition()方法.通过对此代码进行一些调整,您可以将位置传递给侦听器. (78认同)
  • @se_bastiaan`getPosition()`不推荐使用"不推荐使用此方法,因为适配器更新的异步*处理意义不明确.请使用{@link #getLayoutPosition()}或*{@link #getAdapterPosition()}取决于关于你的用例." (26认同)
  • 他完全错过了`onBindViewHolder(holder,position)`,这是信息应该被填充的地方. (13认同)
  • 你有几个选择.将位置放在viewholder中的int字段中,在绑定时更新它,然后在click上返回它是一个. (8认同)
  • @ MLProgrammer-CiM _"你有几个选项.将位置放在视图中的int字段中,在绑定时更新它,然后在点击时返回它是一个."_ ViewHolder已经有了这个值,并且已经设置好了.只需调用`viewHolder.getPosition();` (8认同)
  • 当然*tl:w(on't)r;*是_cool_,但对于复制粘贴SO用户来说,这是很糟糕的_general_建议.请不要为此项目添加RxJava,如果您实际上不知道自己在做什么或者无法证明为什么要让RxJava包装输入,请认真考虑这会产生的开销和可维护性负担事件生成.这只是一个非常深的筹码,只是为了回调.这肯定不是_bad的想法,但请小心. (7认同)
  • @se_bastiaan是的..我的意思是现在已经弃用..即使我使用了这种方法并且赞成了:) (4认同)
  • 为此添加rxJava是一种可怕的膨胀并降低了可维护性.有些地方RxJava很有用,但是如果没有很好的理由将它用于点击处理程序只是一个难以维护的混乱. (3认同)
  • @upenpat现在可能是,现在不是. (2认同)
  • @delive当然,写下这个问题,给我一个100的业力赏金,我会来为你解答. (2认同)
  • @ MLProgrammer-CiM在另一个回答视图.OnClicklistener()被设置为视图,在OnBindViewHolder()中,就像你在VIewHolder类中一样.是另一个人的方式,这是一种不好的做法,因为每次绘制视图时都会分配它.[http://stackoverflow.com/a/28304164/4127441](这里)是答案,如果你没有找到我的问题清楚.谢谢! (2认同)
  • @Raghav两种选择都没关系.他的作品更适合改变的价值,比如位置或与该位置相关的对象.看看我的听众如何只发回视图. (2认同)
  • 在 android 的 stackoverflow 上有史以来最糟糕的被接受的答案......有很多人对它投了赞成票。效率极低。可能是我不明白什么,谁在每次绑定时创建 onclicklistener 可能是一个好方法????它会产生大量的垃圾收集操作。RecyclerView 应该改进 ListView,但是 RecyclerView 的这种使用使它接近相同。 (2认同)
  • WTF 你不需要 PublishSubjects 来处理点击事件,对这篇文章来说完全没有必要。虽然您也不需要 3 级接口。嗯。 (2认同)
  • @Baker,相信我,RxJava 部分不应该在那里,原始帖子才是正确的选择 (2认同)

Dan*_*ato 97

另一种解决方案是由Android GDE的Hugo Visser 提出的解决方案.他为您提供了免费许可课程,您只需输入代码并使用它即可.

用法:

recyclerView.onItemClick { recyclerView, position, v ->
    // do it
}
Run Code Online (Sandbox Code Playgroud)

(它还支持长项目点击)

实施(评论由我添加):

typealias OnRecyclerViewItemClickListener = (recyclerView: RecyclerView, position: Int, v: View) -> Unit
typealias OnRecyclerViewItemLongClickListener = (recyclerView: RecyclerView, position: Int, v: View) -> Boolean

class ItemClickSupport(private val recyclerView: RecyclerView) {

    private var onItemClickListener: OnRecyclerViewItemClickListener? = null
    private var onItemLongClickListener: OnRecyclerViewItemLongClickListener? = null

    private val attachListener: RecyclerView.OnChildAttachStateChangeListener by lazy {
        object : RecyclerView.OnChildAttachStateChangeListener {
            override fun onChildViewAttachedToWindow(view: View) {
                // every time a new child view is attached add click listeners to it
                val holder = this@ItemClickSupport.recyclerView.getChildViewHolder(view)
                        .takeIf { it is ItemClickSupportViewHolder } as? ItemClickSupportViewHolder

                if (onItemClickListener != null && holder?.isClickable != false) {
                    view.setOnClickListener(onClickListener)
                }
                if (onItemLongClickListener != null && holder?.isLongClickable != false) {
                    view.setOnLongClickListener(onLongClickListener)
                }
            }

            override fun onChildViewDetachedFromWindow(view: View) {

            }
        }
    }

    init {
        // the ID must be declared in XML, used to avoid
        // replacing the ItemClickSupport without removing
        // the old one from the RecyclerView
        this.recyclerView.setTag(R.id.item_click_support, this)
        this.recyclerView.addOnChildAttachStateChangeListener(attachListener)
    }

    companion object {
        fun addTo(view: RecyclerView): ItemClickSupport {
            // if there's already an ItemClickSupport attached
            // to this RecyclerView do not replace it, use it
            var support: ItemClickSupport? = view.getTag(R.id.item_click_support) as? ItemClickSupport
            if (support == null) {
                support = ItemClickSupport(view)
            }
            return support
        }

        fun removeFrom(view: RecyclerView): ItemClickSupport? {
            val support = view.getTag(R.id.item_click_support) as? ItemClickSupport
            support?.detach(view)
            return support
        }
    }

    private val onClickListener = View.OnClickListener { v ->
        val listener = onItemClickListener ?: return@OnClickListener
        // ask the RecyclerView for the viewHolder of this view.
        // then use it to get the position for the adapter
        val holder = this.recyclerView.getChildViewHolder(v)
        listener.invoke(this.recyclerView, holder.adapterPosition, v)
    }

    private val onLongClickListener = View.OnLongClickListener { v ->
        val listener = onItemLongClickListener ?: return@OnLongClickListener false
        val holder = this.recyclerView.getChildViewHolder(v)
        return@OnLongClickListener listener.invoke(this.recyclerView, holder.adapterPosition, v)
    }

    private fun detach(view: RecyclerView) {
        view.removeOnChildAttachStateChangeListener(attachListener)
        view.setTag(R.id.item_click_support, null)
    }

    fun onItemClick(listener: OnRecyclerViewItemClickListener?): ItemClickSupport {
        onItemClickListener = listener
        return this
    }

    fun onItemLongClick(listener: OnRecyclerViewItemLongClickListener?): ItemClickSupport {
        onItemLongClickListener = listener
        return this
    }

}

/** Give click-ability and long-click-ability control to the ViewHolder */
interface ItemClickSupportViewHolder {
    val isClickable: Boolean get() = true
    val isLongClickable: Boolean get() = true
}

// Extension function
fun RecyclerView.addItemClickSupport(configuration: ItemClickSupport.() -> Unit = {}) = ItemClickSupport.addTo(this).apply(configuration)

fun RecyclerView.removeItemClickSupport() = ItemClickSupport.removeFrom(this)

fun RecyclerView.onItemClick(onClick: OnRecyclerViewItemClickListener) {
    addItemClickSupport { onItemClick(onClick) }
}
fun RecyclerView.onItemLongClick(onLongClick: OnRecyclerViewItemLongClickListener) {
    addItemClickSupport { onItemLongClick(onLongClick) }
}
Run Code Online (Sandbox Code Playgroud)

还创建一个文件ItemClickSupportViewHolder并将其放入其中:

class MyViewHolder(view): RecyclerView.ViewHolder(view), ItemClickSupportViewHolder {
    override val isClickable: Boolean get() = false
    override val isLongClickable: Boolean get() = false
}
Run Code Online (Sandbox Code Playgroud)

这个类通过附加ViewHoldervalues/ids.xml.每次儿童被附加或分离时,都会通知该听众RecyclerView.OnChildAttachStateChangeListener.代码使用此选项将点击/长按侦听器附加到视图.这听众问RecyclerViewRecyclerView其中包含的位置.

如果您需要更多,您还可以调整代码以便为您提供支持.

请记住,通过在列表的每个视图上设置一个点击监听器,就像其他建议的答案一样,在您的适配器中处理它完全没问题.这不是最有效的事情(每次重复使用视图时都会创建一个新的侦听器),但它可以工作,在大多数情况下它不是问题.

关于为什么 RecyclerView没有RecyclerView.ViewHolder.

onItemClickListener是一个工具箱,RecyclerView与之相反,它具有较少的功能构建和更大的灵活性.这ListView不是从ListView中删除的唯一功能.但它有很多听众和方法可以根据自己的喜好扩展它,它在右手中更强大;).

在我看来,删除的最复杂的功能onItemClickListener快速滚动.大多数其他功能可以轻松重新实现.

  • @DanieleSegato 非常感谢你! (2认同)
  • 当我看到“ItemClickSupport”这样的词时,感觉我们走错了方向。我只是想要一个简单的点击监听器,为什么这么复杂而且不明显! (2认同)

Abd*_*oor 89

我喜欢这种方式而且我正在使用它

public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
Run Code Online (Sandbox Code Playgroud)

View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_image_and_text, parent, false);
v.setOnClickListener(new MyOnClickListener());
Run Code Online (Sandbox Code Playgroud)

并在任何你想要的地方创建这个类

class MyOnClickListener implements View.OnClickListener {
    @Override
    public void onClick(View v) {
       int itemPosition = recyclerView.indexOfChild(v);
       Log.e("Clicked and Position is ",String.valueOf(itemPosition));
    }
}
Run Code Online (Sandbox Code Playgroud)

我以前读过有更好的方法,但我喜欢这种方式很容易而且不复杂.

  • 应该把`MyOnClickListener`变成实例变量,因为每次使用`new`关键字你都会创建它的新实例 (23认同)
  • 如何在MyOnClickListener中获取`recyclerView`? (15认同)
  • recyclerView.getChildPosition(V); 现在使用recyclerView进行删除.indexOfChild(V); (14认同)
  • 滚动时不是有问题吗?在我的测试中,itemPosition似乎依赖于视图回收,因此与我在适配器中的完整列表相比,它出错了. (4认同)
  • 这种形式是可行的,但是这种方法和实现是古老的吗?我认为..如果我们可以使用材料设计,就需要更新此方法吗? (2认同)
  • 而不是使用:int itemPosition = recyclerView.indexOfChild(v); 您应该使用:RecyclerView.ViewHolder持有人= recyclerView.getChildViewHolder(v); int itemPosition = holder.getAdapterPosition(); (2认同)

Gur*_*sad 35

Android Recyclerview With onItemClickListener,为什么我们不能尝试这个只是工作ListView.

来源:链接

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {

private OnItemClickListener mListener;
public interface OnItemClickListener {
    public void onItemClick(View view, int position);
}
GestureDetector mGestureDetector;
public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
    mListener = listener;
    mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return true;
        }
    });
}
@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:

    recyclerView = (RecyclerView)rootView. findViewById(R.id.recyclerView);
    RecyclerView.LayoutManager mLayoutManager = new            LinearLayoutManager(getActivity());
    recyclerView.setLayoutManager(mLayoutManager);
    recyclerView.addOnItemTouchListener(
            new RecyclerItemClickListener(getActivity(), new   RecyclerItemClickListener.OnItemClickListener() {
                @Override
                public void onItemClick(View view, int position) {
                    // TODO Handle item click
                    Log.e("@@@@@",""+position);
                }
            })
    );
Run Code Online (Sandbox Code Playgroud)

  • 老实说没有优雅. (7认同)

Sha*_*yan 23

感谢@marmor,我更新了我的答案.

我认为在ViewHolder类构造函数中处理onClick()并通过OnItemClickListener接口将其传递给父类是一个很好的解决方案.

MyAdapter.java

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

private LayoutInflater layoutInflater;
private List<MyObject> items;
private AdapterView.OnItemClickListener onItemClickListener;

public MyAdapter(Context context, AdapterView.OnItemClickListener onItemClickListener, List<MyObject> items) {
    layoutInflater = LayoutInflater.from(context);
    this.items = items;
    this.onItemClickListener = onItemClickListener;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = layoutInflater.inflate(R.layout.my_row_layout, parent, false);
    return new ViewHolder(view);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    MyObject item = items.get(position);
}

public MyObject getItem(int position) {
    return items.get(position);
}


class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    private TextView title;
    private ImageView avatar;

    public ViewHolder(View itemView) {
        super(itemView);
        title = itemView.findViewById(R.id.title);
        avatar = itemView.findViewById(R.id.avatar);

        title.setOnClickListener(this);
        avatar.setOnClickListener(this);
        itemView.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        //passing the clicked position to the parent class
        onItemClickListener.onItemClick(null, view, getAdapterPosition(), view.getId());
    }
}
}
Run Code Online (Sandbox Code Playgroud)

适配器在其他类中的用法:

MyFragment.java

public class MyFragment extends Fragment implements AdapterView.OnItemClickListener {

private RecyclerView recycleview;
private MyAdapter adapter;

    .
    .
    .

private void init(Context context) {
    //passing this fragment as OnItemClickListener to the adapter
    adapter = new MyAdapter(context, this, items);
    recycleview.setAdapter(adapter);
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    //you can get the clicked item from the adapter using its position
    MyObject item = adapter.getItem(position);

    //you can also find out which view was clicked
    switch (view.getId()) {
        case R.id.title:
            //title view was clicked
            break;
        case R.id.avatar:
            //avatar view was clicked
            break;
        default:
            //the whole row was clicked
    }
}

}
Run Code Online (Sandbox Code Playgroud)

  • 这将在滚动时创建和垃圾收集大量对象,您应该创建一个OnClickListener并重新使用它 (34认同)
  • 滚动时,同一视图也会多次调用`onBindViewHolder()`.即使创建单个"OnClickListener"也无济于事,因为每次调用onBindViewHolder()时都会重置`OnClickListener`.请参阅@ MLProgrammer-CiM解决方案. (2认同)

waq*_*ali 21

伙计们在您的主要活动中使用此代码.非常有效的方法

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.users_list);            
UsersAdapter adapter = new UsersAdapter(users, this);
recyclerView.setAdapter(adapter);
adapter.setOnCardClickListner(this);
Run Code Online (Sandbox Code Playgroud)

这是你的Adapter类.

public class UsersAdapter extends RecyclerView.Adapter<UsersAdapter.UserViewHolder> {
        private ArrayList<User> mDataSet;
        OnCardClickListner onCardClickListner;


        public UsersAdapter(ArrayList<User> mDataSet) {
            this.mDataSet = mDataSet;
        }

        @Override
        public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.user_row_layout, parent, false);
            UserViewHolder userViewHolder = new UserViewHolder(v);
            return userViewHolder;
        }

        @Override
        public void onBindViewHolder(UserViewHolder holder, final int position) {
            holder.name_entry.setText(mDataSet.get(position).getUser_name());
            holder.cardView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onCardClickListner.OnCardClicked(v, position);
                }
            });
        }

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

        @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            super.onAttachedToRecyclerView(recyclerView);
        }


        public static class UserViewHolder extends RecyclerView.ViewHolder {
            CardView cardView;
            TextView name_entry;

            public UserViewHolder(View itemView) {
                super(itemView);
                cardView = (CardView) itemView.findViewById(R.id.user_layout);
                name_entry = (TextView) itemView.findViewById(R.id.name_entry);
             }
        }

        public interface OnCardClickListner {
            void OnCardClicked(View view, int position);
        }

        public void setOnCardClickListner(OnCardClickListner onCardClickListner) {
            this.onCardClickListner = onCardClickListner;
        }
    }
Run Code Online (Sandbox Code Playgroud)

在此之后,您将在活动中获得此覆盖方法.

@Override
    public void OnCardClicked(View view, int position) {
        Log.d("OnClick", "Card Position" + position);
    }
Run Code Online (Sandbox Code Playgroud)

  • 我想知道用户是否向上和向下滚动,OnClickListener将创建并重复循环,它有效吗? (4认同)

Tar*_*ney 19

> RecyclerView与Listview有何不同?

一个区别是有一个LayoutManager使用RecyclerView的课程,您可以通过它管理您的喜欢RecyclerView-

水平或垂直滚动LinearLayoutManager

GridLayout by GridLayoutManager

交错的GridLayout by StaggeredGridLayoutManager

对于RecyclerView的水平滚动 -

LinearLayoutManager llm = new LinearLayoutManager(context);
llm.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(llm);
Run Code Online (Sandbox Code Playgroud)


Bak*_*ker 15

跟进MLProgrammer-CiM卓越的RxJava解决方案

消耗/观察点击次数

Consumer<String> mClickConsumer = new Consumer<String>() {
        @Override
        public void accept(@NonNull String element) throws Exception {
            Toast.makeText(getApplicationContext(), element +" was clicked", Toast.LENGTH_LONG).show();
        }
    };

ReactiveAdapter rxAdapter = new ReactiveAdapter();
rxAdapter.getPositionClicks().subscribe(mClickConsumer);
Run Code Online (Sandbox Code Playgroud)

RxJava 2. +

修改原始tl; dr为:

public Observable<String> getPositionClicks(){
    return onClickSubject;
}
Run Code Online (Sandbox Code Playgroud)

PublishSubject#asObservable()去掉了.只需返回PublishSubject哪个是Observable.


Woo*_*off 14

如何把它们放在一起的例子......

  • onClick()处理
  • 光标 - RecyclerView
  • ViewHolder类型

    public class OrderListCursorAdapter extends CursorRecyclerViewAdapter<OrderListCursorAdapter.ViewHolder> {
    
    private static final String TAG = OrderListCursorAdapter.class.getSimpleName();
    private static final int ID_VIEW_HOLDER_ACTUAL = 0;
    private static final int ID_VIEW_HOLDER = 1;
    
    public OrderListCursorAdapter(Context context, Cursor cursor) {
        super(context, cursor);
    }
    
    public static class ViewHolderActual extends ViewHolder {
        private static final String TAG = ViewHolderActual.class.getSimpleName();
        protected IViewHolderClick listener;
        protected Button button;
    
        public ViewHolderActual(View v, IViewHolderClick listener) {
            super(v, listener);
            this.listener = listener;
            button = (Button) v.findViewById(R.id.orderList_item_button);
            button.setOnClickListener(this);
        }
    
        public void initFromData(OrderData data) {
            Log.d(TAG, "><initFromData(data=" + data + ")");
            orderId = data.getId();
            vAddressStart.setText(data.getAddressStart());
            vAddressEnd.setText(data.getAddressEnd());
        }
    
        @Override
        public void onClick(View view) {
            if (view instanceof Button) {
                listener.onButtonClick((Button) view, getPosition(), this);
            } else {
                super.onClick(view);
            }
        }
    
        public interface IViewHolderClick extends ViewHolder.IViewHolderClick {
            public void onButtonClick(Button button, int position, ViewHolder viewHolder);
        }
    }
    
    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        private static final String TAG = ViewHolder.class.getSimpleName();
        protected long orderId;
        protected IViewHolderClick listener;
        protected TextView vAddressStart;
        protected TextView vAddressEnd;
        protected TextView vStatus;
    
        public ViewHolder(View v, IViewHolderClick listener) {
            super(v);
            this.listener = listener;
            v.setOnClickListener(this);
    
            vAddressStart = (TextView) v.findViewById(R.id.addressStart);
            vAddressEnd = (TextView) v.findViewById(R.id.addressEnd);
            vStatus = (TextView) v.findViewById(R.id.status);
        }
    
        public void initFromData(OrderData data) {
            Log.d(TAG, "><initFromData(data=" + data + ")");
            orderId = data.getId();
            vAddressStart.setText(data.getAddressStart());
            vAddressEnd.setText(data.getAddressEnd());
        }
    
        public long getOrderId() {
            return orderId;
        }
    
        @Override
        public void onClick(View view) {
            listener.onCardClick(view, getPosition(), this);
        }
    
        public interface IViewHolderClick {
            public void onCardClick(View view, int position, ViewHolder viewHolder);
        }
    }
    
    @Override
    public int getItemViewType(int position) {
        return position == 0 ? ID_VIEW_HOLDER_ACTUAL : ID_VIEW_HOLDER;
    }
    
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Log.d(TAG, ">>onCreateViewHolder(parent=" + parent + ", viewType=" + viewType + ")");
    
        ViewHolder result;
    
        switch (viewType) {
            case ID_VIEW_HOLDER_ACTUAL: {
                View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout_actual, parent, false);
                result = new ViewHolderActual(itemView, new ViewHolderActual.IViewHolderClick() {
                    @Override
                    public void onCardClick(View view, int position, ViewHolder viewHolder) {
                        Log.d(TAG, "><onCardClick(view=" + view + ", position=" + position + ", viewHolder=" + viewHolder + ")");
                        Intent intent = new Intent(view.getContext(), OrderDetailActivity.class);
                        intent.putExtra(OrderDetailActivity.ARG_ORDER_ID, viewHolder.getOrderId());
                        view.getContext().startActivity(intent);
                    }
    
                    @Override
                    public void onButtonClick(Button button, int position, ViewHolder viewHolder) {
                        Log.d(TAG, "><onButtonClick(button=" + button + ", position=" + position + ", viewHolder=" + viewHolder + ")");
                        Intent intent = new Intent(button.getContext(), OrderMapActivity.class);
                        intent.putExtra(OrderMapActivity.ARG_ORDER_ID, viewHolder.getOrderId());
                        button.getContext().startActivity(intent);
                    }
                });
                break;
            }
            case ID_VIEW_HOLDER:
            default: {
                View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout, parent, false);
                result = new ViewHolder(itemView, new ViewHolder.IViewHolderClick() {
                    @Override
                    public void onCardClick(View view, int position, ViewHolder viewHolder) {
                        Log.d(TAG, "><onCardClick(view=" + view + ", position=" + position + ", viewHolder=" + viewHolder + ")");
                        Intent intent = new Intent(view.getContext(), OrderDetailActivity.class);
                        intent.putExtra(OrderDetailActivity.ARG_ORDER_ID, viewHolder.getOrderId());
                        view.getContext().startActivity(intent);
                    }
                });
                break;
            }
        }
    
        Log.d(TAG, "<<onCreateViewHolder(parent=" + parent + ", viewType=" + viewType + ")= " + result);
        return result;
    }
    
    @Override
    public void onBindViewHolder(ViewHolder viewHolder, Cursor cursor) {
        Log.d(TAG, "><onBindViewHolder(viewHolder=" + viewHolder + ", cursor=" + cursor + ")");
        final OrderData orderData = new OrderData(cursor);
        viewHolder.initFromData(orderData);
    }
    }
    
    Run Code Online (Sandbox Code Playgroud)


Tom*_*zyk 10

据我所知,MLProgrammer-CiM 答案,只需要这样做:

class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
    private ImageView image;
    private TextView title;
    private TextView price;

    public MyViewHolder(View itemView) {
        super(itemView);
        image = (ImageView)itemView.findViewById(R.id.horizontal_list_image);
        title = (TextView)itemView.findViewById(R.id.horizontal_list_title);
        price = (TextView)itemView.findViewById(R.id.horizontal_list_price);
        image.setOnClickListener(this);
        title.setOnClickListener(this);
        price.setOnClickListener(this);
    }


    @Override
    public void onClick(View v) {
        Toast.makeText(context, "Item click nr: "+getLayoutPosition(), Toast.LENGTH_SHORT).show();
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 9

阅读@ MLProgrammer-CiM的回答后,这是我的代码:

class NormalViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

    @Bind(R.id.card_item_normal)
    CardView cardView;

    public NormalViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
        cardView.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if(v instanceof CardView) {
            // use getAdapterPosition() instead of getLayoutPosition()
            int itemPosition = getAdapterPosition();
            removeItem(itemPosition);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Hir*_*tel 9

我这样做了,非常简单:

只需为Clicked RecyclerView位置添加1行:

int position = getLayoutPosition()
Run Code Online (Sandbox Code Playgroud)

ViewHolder类的完整代码:

private class ChildViewHolder extends RecyclerView.ViewHolder {
        public ImageView imageView;
        public TextView txtView;

        public ChildViewHolder(View itemView) {
            super(itemView);
            imageView= (ImageView)itemView.findViewById(R.id.imageView);
            txtView= (TextView) itemView.findViewById(R.id.txtView);
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Log.i("RecyclerView Item Click Position", String.valueOf(getLayoutPosition()));
                }
            });
        }
    }
Run Code Online (Sandbox Code Playgroud)

希望这会帮助你.


tma*_*c12 6

我使用这个方法从RecyclerView启动一个Intent:

@Override
 public void onBindViewHolder(ViewHolder viewHolder, int i) {

    final MyClass myClass = mList.get(i);
    viewHolder.txtViewTitle.setText(myclass.name);
   ...
    viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
      @Override
       public void onClick(View v){
             Intent detailIntent = new Intent(mContext, type.class);                                                            
             detailIntent.putExtra("MyClass", myclass);
             mContext.startActivity(detailIntent);
       }
}
);
Run Code Online (Sandbox Code Playgroud)


Ale*_*cus 5

请参阅我的方法:

首先声明一个这样的接口:

/**
 * Interface used for delegating item click events in a {@link android.support.v7.widget.RecyclerView}
 * Created by Alex on 11/28/2015.
 */
  public interface OnRecyclerItemClickListener<T> {

     /**
      * Called when a click occurred inside a recyclerView item view
      * @param view that was clicked
      * @param position of the clicked view
      * @param item the concrete data that is displayed through the clicked view
      */
      void onItemClick(View view, int position, T item);
   }
Run Code Online (Sandbox Code Playgroud)

然后创建适配器:

public class CustomRecyclerAdapter extends RecyclerView.Adapter {      

    private class InternalClickListener implements View.OnClickListener{

      @Override
      public void onClick(View v) {
        if(mRecyclerView != null && mItemClickListener != null){
            // find the position of the item that was clicked
            int position = mRecyclerView.getChildAdapterPosition(v);
            Data data = getItem(position);
            // notify the main listener
            mItemClickListener.onItemClick(v, position, data);
        }
    }
}

private final OnRecyclerItemClickListener mItemClickListener;
private RecyclerView mRecyclerView;    
private InternalClickListener mInternalClickListener;


/**
 *
 * @param itemClickListener used to trigger an item click event
 */
public PlayerListRecyclerAdapter(OnRecyclerItemClickListener itemClickListener){        
    mItemClickListener = itemClickListener;
    mInternalClickListener = new InternalClickListener();
}

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

    v.setOnClickListener(mInternalClickListener);

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

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    // do your binding here
}

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

@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);

    mRecyclerView = recyclerView;
}

@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
    super.onDetachedFromRecyclerView(recyclerView);

    mRecyclerView = null;
}

public Data getItem(int position){
    return mDataset.get(position);
}
}
Run Code Online (Sandbox Code Playgroud)

现在让我们看看如何从片段中集成它:

public class TestFragment extends Fragment implements OnRecyclerItemClickListener<Data>{
   private RecyclerView mRecyclerView;

   @Override
   public void onItemClick(View view, int position, Data item) {
     // do something
   }

   @Override
   public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      return inflater.inflate(R.layout.test_fragment, container, false);
   }

   @Override
   public void onViewCreated(View view, Bundle savedInstanceState) {
      mRecyclerView = view.findViewById(idOfTheRecycler);
      mRecyclerView .setAdapter(new CustomRecyclerAdapter(this));
   }
Run Code Online (Sandbox Code Playgroud)


cry*_*yyy 5

如果你想将 onClick() 添加到 item 的子视图中,例如 item 中的一个按钮,我发现你可以在你自己的 RecyclerView.Adapter 的 onCreateViewHolder() 中轻松完成,就像这样:

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View v = LayoutInflater
                    .from(parent.getContext())
                    .inflate(R.layout.cell, null);

            Button btn = (Button) v.findViewById(R.id.btn);
            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //do it
                }
            });

            return new MyViewHolder(v);
        }
Run Code Online (Sandbox Code Playgroud)

我不知道这是否是一个好方法,但它运作良好。如果有人有更好的主意,很高兴告诉我并纠正我的答案!:)


Sim*_*mon 5

如果您有一个POJO列表并希望从适配器外部单击检索一个POJO,则可以非常轻松地实现它.

在适配器中,为click事件创建一个侦听器,并设置一个方法来设置它:

public class MyAdapter extends RecyclerView.Adapter<SitesListAdapter.ViewHolder> {
...
private List<MyPojo> mMyPojos;
private static OnItemClickListener mOnItemClickListener;

...
public interface OnItemClickListener {
    public void onItemClick(MyPojo pojo);
}

...
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
    mOnItemClickListener = onItemClickListener;
}
...
Run Code Online (Sandbox Code Playgroud)

}

在ViewHolder中,实现onClickListener并创建一个类成员来临时存储视图所呈现的POJO(这是一个例子,创建一个setter会更好):

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    public MyPojo mCurrentPojo;
    ...
    public ViewHolder(View view) {
        super(v);
        ...
        view.setOnClickListener(this); //You could set this on part of the layout too
    }

    ...
    @Override
    public void onClick(View view) {
        if(mOnItemClickListener != null && mCurrentPojo != null){
            mOnItemClickListener.onItemClick(mCurrentPojo);
        }
    }
Run Code Online (Sandbox Code Playgroud)

返回适配器,在绑定ViewHolder时设置当前POJO(如果当前视图没有,则设置为null):

@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
    final MyPojo currentPojo = mMyPojos.get(position); 
    holder.mCurrentPojo = currentPojo;
    ...
Run Code Online (Sandbox Code Playgroud)

就是这样,现在你可以从你的片段/活动中使用它:

    mMyAdapter.setOnItemClickListener(new mMyAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(MyPojo pojo) {
            //Do whatever you want with your pojo here
        }
    });
Run Code Online (Sandbox Code Playgroud)


Epi*_*rce 5

RecyclerView没有onItemClickListener原因,因为RecyclerView负责回收视图(惊奇!),因此回收视图以处理接收到的点击事件是视图的责任。

实际上,这使它使用起来更加容易,尤其是当您具有可以在多个位置单击的项目时。


无论如何,检测RecyclerView项目上的点击非常容易。您需要做的就是定义一个接口(如果您不使用Kotlin,在这种情况下,您只需传入一个lambda):

public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
    private final Clicks clicks;

    public MyAdapter(Clicks clicks) {
        this.clicks = clicks;
    }

    private List<MyObject> items = Collections.emptyList();

    public void updateData(List<MyObject> items) {
        this.items = items;
        notifyDataSetChanged(); // TODO: use ListAdapter for diffing instead if you need animations
    }

    public interface Clicks {
        void onItemSelected(MyObject myObject, int position);
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        private MyObject myObject;    

        public MyViewHolder(View view) {
            super(view);
            // bind views
            view.setOnClickListener((v) -> {
                int adapterPosition = getAdapterPosition();
                if(adapterPosition >= 0) {
                    clicks.onItemSelected(myObject, adapterPosition);
                }
            });
        }

        public void bind(MyObject myObject) {
            this.myObject = myObject;
            // bind data to views
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Kotlin中的相同代码:

class MyAdapter(val itemClicks: (MyObject, Int) -> Unit): RecyclerView.Adapter<MyViewHolder>() {
    private var items: List<MyObject> = Collections.emptyList()

    fun updateData(items: List<MyObject>) {
        this.items = items
        notifyDataSetChanged() // TODO: use ListAdapter for diffing instead if you need animations
    }

    inner class MyViewHolder(val myView: View): RecyclerView.ViewHolder(myView) {
        private lateinit var myObject: MyObject

        init {
            // binds views
            myView.onClick {
                val adapterPosition = getAdapterPosition()
                if(adapterPosition >= 0) {
                    itemClicks.invoke(myObject, adapterPosition)
                }
            }
        }

        fun bind(myObject: MyObject) {
            this.myObject = myObject
            // bind data to views
        }
    }
}
Run Code Online (Sandbox Code Playgroud)