为什么RecyclerView没有onItemClickListener()?

 手机用户2502891227 发布于 2023-01-01 18:02

我正在探索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) {

    }
}

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

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

15 个回答
  • 据我所知,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();
        }
    }
    

    2023-01-01 18:03 回答
  • > 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);
    

    2023-01-01 18:04 回答
  • 伙计们在您的主要活动中使用此代码.非常有效的方法

    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.users_list);            
    UsersAdapter adapter = new UsersAdapter(users, this);
    recyclerView.setAdapter(adapter);
    adapter.setOnCardClickListner(this);
    

    这是你的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;
            }
        }
    

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

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

    2023-01-01 18:04 回答
  • 跟进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);
    

    RxJava 2. +

    修改原始tl; dr为:

    public Observable<String> getPositionClicks(){
        return onClickSubject;
    }
    

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

    2023-01-01 18:04 回答
  • 如何把它们放在一起的例子......

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

    2023-01-01 18:04 回答
  • 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
            }
        }
    }
    

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

    2023-01-01 18:04 回答
  • 如果您有一个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;
    }
    ...
    

    }

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

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

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

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

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

    2023-01-01 18:04 回答
  • 我这样做了,非常简单:

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

    int position = getLayoutPosition()
    

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

    希望这会帮助你.

    2023-01-01 18:05 回答
  • 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();
        }
    }
    

    原帖:

    自推出以来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);
        }
    
    }
    

    然后在你的适配器上

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

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

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

    2023-01-01 18:05 回答
  • 阅读@ 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);
            }
        }
    }
    

    2023-01-01 18:05 回答
  • 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) {
    
      }
    }
    

    并将其设置为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);
                    }
                })
        );
    

    2023-01-01 18:05 回答
  • 我使用这个方法从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);
           }
    }
    );
    

    2023-01-01 18:05 回答
  • 我喜欢这种方式而且我正在使用它

    public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    

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

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

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

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

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

    用法:

    recyclerView.onItemClick { recyclerView, position, v ->
        // do it
    }
    

    (它还支持长项目点击)

    实施(评论由我添加):

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

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

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

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

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

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

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

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

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

    2023-01-01 18:05 回答
  • 感谢@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());
        }
    }
    }
    

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

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

    2023-01-01 18:05 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有