ChatGPT解决这个技术问题 Extra ChatGPT

为什么 RecyclerView 没有 onItemClickListener()?

我正在探索 RecyclerView,我惊讶地发现 RecyclerView 没有 onItemClickListener()

我有两个问题。

主要问题

我想知道为什么 Google 删除了 onItemClickListener()

是否存在性能问题或其他问题?

次要问题

我通过在 RecyclerView.Adapter 中写入 onClick 解决了我的问题:

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

    }
}

这可以吗/有没有更好的方法?

要使您的代码正常工作,您需要添加 itemLayoutView.setOnClickListener(this);在 ViewHolder 构造函数中。
你问了很好的问题......许多开发人员对 RecyclerView 和 ListView 有同样的疑问。
问题:为什么 RecyclerView 没有 OnItemClickListner() ?以下除 2 外的所有答案:如何为 RecyclerView 添加 onclick
希望有人真的抽出时间来回答QUESTION
我认为他们删除它是因为性能和垃圾内存问题。但是看看接受的答案......它会产生同样的问题。我认为你接受它是错误的,现在其他人因为你犯了错误:)。

M
Maragues

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 视为 ListView 1: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 的内部实现和改进非常接近。谷歌终于承认了这一点,这很好。


RecyclerView.ViewHolder 有一个 getPosition() 方法。通过对此代码进行一些调整,您可以将位置传递给侦听器。
他完全错过了 onBindViewHolder(holder, position) ,这是应该填写信息的地方。
@se_bastiaan getPosition() 已弃用“此方法已弃用,因为由于适配器更新的异步处理,其含义不明确。请使用 {@link #getLayoutPosition()} 或 * {@link #getAdapterPosition()},具体取决于您的用例。”
你有几个选择。将位置放在 viewholder 内的 int 字段中,在绑定时更新它,然后在单击时返回它是一个。
@MLProgrammer-CiM “你有几个选择。将位置放在视图支架内的 int 字段中,在绑定时更新它,然后单击返回它是一个。” ViewHolder 已经有这个值,并且已经设置好了。只需拨打 viewHolder.getPosition();
D
Daniele Segato

为什么 RecyclerView 没有 onItemClickListener

RecyclerView 是一个工具箱,与旧的 ListView 相比,它的内置功能更少,灵活性更高。 onItemClickListener 不是从 ListView 中删除的唯一功能。但是它有很多听众和方法可以根据你的喜好扩展它,它在右手中要强大得多;)。

在我看来,RecyclerView 中删除的最复杂的功能是 Fast Scroll。大多数其他功能都可以轻松地重新实现。

如果您想知道 RecyclerView 添加了哪些其他很酷的功能,请阅读 this 回答另一个问题。

内存高效 - onItemClickListener 的插入式解决方案

该解决方案由 Android GDE 的 Hugo VisserRecyclerView 发布后proposed提供。他为您提供了一个免许可证课程,您只需放入您的代码并使用它。

它通过使用 RecyclerView.OnChildAttachStateChangeListener 展示了 RecyclerView 引入的一些多功能性。

编辑 2019:我的 kotlin 版本,Java 版本,来自 Hugo Visser,保留在下面

科特林/Java

创建一个文件 values/ids.xml 并将其放入其中:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="item_click_support" type="id" />
</resources>

然后将下面的代码添加到您的源

科特林

用法:

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

(它还支持长项目点击,我添加的另一个功能见下文)。

实现(我对 Hugo Visser Java 代码的改编):

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

class ItemClickSupport private constructor(private val recyclerView: RecyclerView) {

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

    private val attachListener: RecyclerView.OnChildAttachStateChangeListener = 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) }
}

(请记住,您还需要添加一个 XML 文件,请参阅本节上方)

Kotlin 版本的额外功能

有时您不希望 RecyclerView 的所有项目都是可点击的。

为了解决这个问题,我引入了 ItemClickSupportViewHolder 界面,您可以在 ViewHolder 上使用它来控制可点击的项目。

例子:

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

爪哇

用法:

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

(它也支持长项目点击)

实施(我添加的评论):

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) {
                // ask the RecyclerView for the viewHolder of this view.
                // then use it to get the position for the adapter
                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) {
            // every time a new child view is attached add click listeners to it
            if (mOnItemClickListener != null) {
                view.setOnClickListener(mOnClickListener);
            }
            if (mOnItemLongClickListener != null) {
                view.setOnLongClickListener(mOnLongClickListener);
            }
        }

        @Override
        public void onChildViewDetachedFromWindow(View view) {

        }
    };

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

    public static ItemClickSupport addTo(RecyclerView view) {
        // if there's already an ItemClickSupport attached
        // to this RecyclerView do not replace it, use it
        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);
    }
}

它是如何工作的(为什么它是有效的)

此类通过将 RecyclerView.OnChildAttachStateChangeListener 附加到 RecyclerView 来工作。每次从 RecyclerView 附加或分离子项时,都会通知此侦听器。代码使用它来将点击/长按侦听器附加到视图。该侦听器向 RecyclerView 询问包含该位置的 RecyclerView.ViewHolder

这比其他解决方案更有效,因为它避免为每个视图创建多个侦听器,并在 RecyclerView 滚动时不断销毁和创建它们。

如果您需要更多,您还可以调整代码以将持有人返还给您。

最后的评论

请记住,通过在列表的每个视图上设置一个单击侦听器来在适配器中处理它是完全可以的,就像其他建议的答案一样。

这不是最有效的做法(每次重用视图时都会创建一个新的侦听器),但它可以工作,并且在大多数情况下这不是问题。

这也有点反对关注点分离,因为委托点击事件并不是适配器的真正工作。


addOnChildAttachStateChangeListener 在构造函数中并且从不删除它?
@Saba 您不应该直接使用构造函数,而是通过静态方法 addTo()removeFrom()。该实例与 recyclerview 标签相关联,并随着它或被手动删除而死亡。
当您需要做的就是在 onCreateViewHolder 中设置一个点击监听器时,就需要这么多的代码,仅此而已。
您的论点很流畅,这与代码的数量无关,而是与效率和责任原则有关,并且代码的数量并不是解决方案好坏的重要指标,尤其是当该代码可重用且高效时。将该代码放入您的项目(您可以将其视为库包含)后,您只需要在 RecyclerView 上添加一个 1-liner。
@DanieleSegato 非常感谢您!
v
vishal dharankar

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

里面

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

我以前读过有更好的方法,但我喜欢这种方法简单而不复杂。


可能应该将 MyOnClickListener 变成实例变量,因为您每次都会使用 new 关键字创建它的新实例
recyclerView.getChildPosition(v);被贬低现在使用recyclerView。 indexOfChild(v);
滚动时没有问题吗?在我的测试中,itemPosition 似乎依赖于视图回收,因此与我在适配器中的完整列表相比它出错了。
如何在 MyOnClickListener 中获取 recyclerView
而不是使用: int itemPosition = recyclerView.indexOfChild(v);你应该使用: RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(v); int itemPosition = holder.getAdapterPosition();
C
ColdFire

Android Recyclerview 使用 onItemClickListener,为什么我们不能尝试这只是像 ListView 一样工作。

来源:Link

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

老实说,没有优雅。
@vishaldharankar 为什么不呢?我认为这是避免使用 SwipeRefreshLayout 后焦点更改冲突的最佳方法
这完全没有必要,您可以使用 View.OnClickListener 而不是拦截触摸。
S
Shayan_Aryan

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

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

我的适配器.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
    }
}

}

这将在滚动时创建并收集大量对象,您应该创建一个 OnClickListener 并重新使用它
滚动时,同一视图也会多次调用 onBindViewHolder()。即使创建单个 OnClickListener 也无济于事,因为您将在每次调用 onBindViewHolder() 时重置 OnClickListener。请参阅@MLProgrammer-CiM 解决方案。
您还可以改进@MLProgrammer-CiM 解决方案,而不是为此行MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() .... 中的每个视图创建一个侦听器对象,您可以为所有视图创建一个侦听器。
w
waqas ali

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

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

这是您的适配器类。

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

我想知道如果用户向上和向下滚动,OnClickListener 将创建并被一遍又一遍地回收,它有效吗?
为了获得卡片的更新位置,这个小东西可以被妥协。
嗨,朋友,它的工作魅力很好,我最初有一个包含类别和产品的需求活动,如果用户选择类别图标,我需要在对话框或活动中显示类别如果用户选择任何基于将过滤数据加载到第一个活动的类别,请帮助我怎么解决
第一:您需要在接口 OnCardClickListner 中添加一个名为 OnProductClicked 的方法,就像这个 public interface OnCardClickListner { void OnCardClicked(View view, int position); void OnProductClicked(查看视图,int 位置);第二:然后像这样在您的产品图标上实现点击监听器。 holder.yourProductIcon.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onCardClickListner.OnProductClicked (v, position); } });
我无法覆盖 OnCardClicked。人们如何支持这个答案?
Z
Ziem

> RecyclerView 与 Listview 有何不同?

一个区别是 RecyclerView 有 LayoutManager 类,您可以通过它管理您的 RecyclerView,例如 -

LinearLayoutManager 水平或垂直滚动 GridLayoutManager GridLayout StaggeredGridLayoutManager 交错 GridLayout

就像 RecyclerView 的水平滚动一样-

LinearLayoutManager llm = new LinearLayoutManager(context);
llm.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(llm);

C
Community

如何将它们放在一起示例...

onClick() 处理

光标 - RecyclerView

ViewHolder 类型 public class OrderListCursorAdapter extends CursorRecyclerViewAdapter { private static final String TAG = OrderListCursorAdapter.class.getSimpleName();私有静态最终 int ID_VIEW_HOLDER_ACTUAL = 0;私有静态最终 int ID_VIEW_HOLDER = 1;公共 OrderListCursorAdapter(上下文上下文,光标光标){ 超级(上下文,光标); } 公共静态类 ViewHolderActual 扩展 ViewHolder { 私有静态最终字符串 TAG = ViewHolderActual.class.getSimpleName();受保护的 IViewHolderClick 监听器;受保护的按钮按钮; public ViewHolderActual(View v, IViewHolderClick listener) { super(v, listener); this.listener = 监听器; button = (Button) v.findViewById(R.id.orderList_item_button); button.setOnClickListener(this); } public void initFromData(OrderData data) { Log.d(TAG, ">>onCreateViewHolder(parent=" + parent + ", viewType=" + viewType + ")"); ViewHolder 结果; switch (viewType) { case ID_VIEW_HOLDER_ACTUAL: { 查看 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, ">


H
Hadas Kaminsky

跟进MLProgrammer-CiM's excellent RxJava solution

消费/观察点击

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() 已删除。只需返回作为 ObservablePublishSubject


你在哪里得到第二行的 mClickConsumer,如果你能解释一下。 rxAdapter.getPositionClicks().subscribe(mClickConsumer);
Z
ZygD

据我了解 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();
    }
}

E
EpicPandaForce

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

你不需要做的事情:

1.)您不需要手动拦截触摸事件

2.) 你不需要弄乱子附加状态更改侦听器

3.) 你不需要来自 RxJava 的 PublishSubject/PublishRelay

只需使用点击监听器。


视频中没有onClick处理?
Checkout 0:45 在视频中有一个 onClickListener 附加在适配器中
c
chad

阅读@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);
        }
    }
}

请注意,getAdapterPosition 可能会为“无位置”返回 -1
H
Hiren Patel

我已经这样做了,它非常简单:

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

希望这会帮助你。


您应该使用 getAdapterPosition 而不是 getLayoutPosition。防范-1
t
tmac12

我使用此方法从 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);
       }
}
);

这不是好办法。因为在 notify() 方法之后没有调用 onBindViewHolder(...)。因此,在某些情况下,您可能会得到错误的点击位置。
A
Alexandru Circus

请参阅我的方法:

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

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

然后创建适配器:

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

现在让我们看看如何从片段中整合它:

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

c
cryyyyy

如果你想在item的子视图中添加onClick(),例如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);
        }

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


S
Simon

如果您有一个 POJO 列表并希望从适配器外部单击时检索一个 POJO,那么这是一种非常容易实现它的方法。

在您的适配器中,为单击事件创建一个侦听器和一个设置它的方法:

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

您正在尝试实现接口,就好像它是一个对象方法一样。这行不通
更新:您需要的是 mMyAdapter.setOnItemClickListener(MyAdapter.OnItemClickListener() {});
@Akshay对不起,但我认为我的代码是正确的。你试过了吗? Android 上的所有监听器都遵循相同的原则,您需要使用“新”实例化接口(例如:stackoverflow.com/questions/4709870/…
侦听器不应该是静态的。
N
Nikolay Mihaylov

是的你可以

public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {

    //inflate the view 

    View view = LayoutInflator.from(parent.getContext()).inflate(R.layout.layoutID,null);

    ViewHolder holder = new ViewHolder(view);

    //here we can set onClicklistener
    view.setOnClickListener(new  View.OnClickListeener(){
        public void onClick(View v)
        {
            //action
        }
    });

return holder;

N
Naren

这对我有用:

@Override
public void onBindViewHolder(PlacesListViewAdapter.ViewHolder holder, int position) {
    ----
    ----
    ----
    // Set setOnClickListener(holder);
}


@Override
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    ----
    ----
    ----

    @Override
    public void onClick(View view) {
        // Use to get the item clicked getAdapterPosition()
    }
}

onBindViewHolder() 中设置 setOnClickListener(holder) 不是好方法。因为 onBindViewHolder(...) 在 notify() 方法之后没有被调用。因此,在某些情况下,您可能会得到错误的点击位置。
您应该在 onCreateViewHolder 内创建点击侦听器。
A
Arpit Patel

在这里您可以处理多个onclick,请参见下面的代码,它非常有效

    public class RVNewsAdapter extends RecyclerView.Adapter<RVNewsAdapter.FeedHolder> {

    private Context context;
    List<News> newsList;
    // Allows to remember the last item shown on screen
    private int lastPosition = -1;

    public RVNewsAdapter(List<News> newsList, Context context) {
        this.newsList = newsList;
        this.context = context;
    }

    public static class FeedHolder extends RecyclerView.ViewHolder implements OnClickListener {

        ImageView img_main;
        TextView tv_title;
        Button bt_facebook, bt_twitter, bt_share, bt_comment;


        public FeedHolder(View itemView) {
            super(itemView);

            img_main = (ImageView) itemView.findViewById(R.id.img_main);
            tv_title = (TextView) itemView.findViewById(R.id.tv_title);
            bt_facebook = (Button) itemView.findViewById(R.id.bt_facebook);
            bt_twitter = (Button) itemView.findViewById(R.id.bt_twitter);
            bt_share = (Button) itemView.findViewById(R.id.bt_share);
            bt_comment = (Button) itemView.findViewById(R.id.bt_comment);

            img_main.setOnClickListener(this);
            bt_facebook.setOnClickListener(this);
            bt_twitter.setOnClickListener(this);
            bt_comment.setOnClickListener(this);
            bt_share.setOnClickListener(this);

        }


        @Override
        public void onClick(View v) {

            if (v.getId() == bt_comment.getId()) {

                Toast.makeText(v.getContext(), "Comment  " , Toast.LENGTH_SHORT).show();

            } else if (v.getId() == bt_facebook.getId()) {

                Toast.makeText(v.getContext(), "Facebook  " , Toast.LENGTH_SHORT).show();

            } else if (v.getId() == bt_twitter.getId()) {

                Toast.makeText(v.getContext(), "Twitter  " , Toast.LENGTH_SHORT).show();

            } else if (v.getId() == bt_share.getId()) {

                Toast.makeText(v.getContext(), "share  " , Toast.LENGTH_SHORT).show();

            }
            else {
                Toast.makeText(v.getContext(), "ROW PRESSED = " + String.valueOf(getAdapterPosition()), Toast.LENGTH_SHORT).show();
            }
        }
    }

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

    @Override
    public FeedHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.feed_row, parent, false);
        FeedHolder feedHolder = new FeedHolder(view);

        return feedHolder;
    }

    @Override
    public void onBindViewHolder(FeedHolder holder, int position) {

        holder.tv_title.setText(newsList.get(position).getTitle());


        // Here you apply the animation when the view is bound
        setAnimation(holder.img_main, position);
    }

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


    /**
     * Here is the key method to apply the animation
     */
    private void setAnimation(View viewToAnimate, int position) {
        // If the bound view wasn't previously displayed on screen, it's animated
        if (position > lastPosition) {
            Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
            viewToAnimate.startAnimation(animation);
            lastPosition = position;
        }
    }


}

他的意思是itemView
O
OneCricketeer

修改了我的评论...

public class MyViewHolder extends RecyclerView.ViewHolder {

        private Context mContext;

        public MyViewHolder(View itemView) {
            super(itemView);

            mContext = itemView.getContext();

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {

                    int itemPosition = getLayoutPosition();
                    Toast.makeText(mContext, "" + itemPosition, Toast.LENGTH_SHORT).show();

                }
            });
        }

这是一个建议,但如果您删除此答案会更好,除非很多人会投反对票。这个解决方案绝对是错误的,它可以工作,但编程不好。请阅读 RecyclerView 的一些博客并学习一些 Adapter 库,Github 中已经有很多有效的,如 FlexibleAdapter、FastAdapter 等...
您的回答是一长串高投票答案中相对较新的答案,并且在页面底部,这就是它仍然有 0 票的原因。顺便说一句,在新代码中,您应该使用 getAdapterPosition()
M
Mudassir Khan

检查这个我以正确的方式实现了所有东西的地方

RecyclerViewHolder 类

public class RecyclerViewHolder extends RecyclerView.ViewHolder  {

    //view holder is for girdview as we used in the listView
    public ImageView imageView,imageView2;
    public RecyclerViewHolder(View itemView) {
        super(itemView);
        this.imageView=(ImageView)itemView.findViewById(R.id.image);
    }

}

适配器

public class RecyclerView_Adapter extends RecyclerView.Adapter<RecyclerViewHolder> {

    //RecyclerView will extend to recayclerview Adapter
    private ArrayList<ModelClass> arrayList;
    private Context context;
    private static RecyclerViewClickListener itemListener;
    //constructor of the RecyclerView Adapter
    RecyclerView_Adapter(Context context,ArrayList<ModelClass> arrayList,RecyclerViewClickListener itemListener){
        this.context=context;
        this.arrayList=arrayList;
        this.itemListener=itemListener;
    }

    @Override
    public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //this method will inflate the custom layout and return as viewHolder
        LayoutInflater layoutInflater=LayoutInflater.from(parent.getContext());
        ViewGroup mainGroup=(ViewGroup) layoutInflater.inflate(R.layout.single_item,parent,false);
        RecyclerViewHolder listHolder=new RecyclerViewHolder(mainGroup);

        return listHolder;
    }

    @Override
    public void onBindViewHolder(RecyclerViewHolder holder, final int position) {

        final ModelClass modelClass=arrayList.get(position);
        //holder
        RecyclerViewHolder mainHolder=(RecyclerViewHolder)holder;
        //convert the drawable image into bitmap
        Bitmap image= BitmapFactory.decodeResource(context.getResources(),modelClass.getImage());
        //set the image into imageView
        mainHolder.imageView.setImageBitmap(image);
        //to handle on click event when clicked on the recyclerview item and
        // get it through the RecyclerViewHolder class we have defined the views there
        mainHolder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //get the position of the image which is clicked
             itemListener.recyclerViewListClicked(v,position);
            }
        });

    }

    @Override
    public int getItemCount() {
        return (null!=arrayList?arrayList.size():0);
    }
}

界面

public interface RecyclerViewClickListener {

    //this is method to handle the event when clicked on the image in Recyclerview
    public void recyclerViewListClicked(View v,int position);
}

//and to call this method in activity
RecyclerView_Adapter adapter=new RecyclerView_Adapter(Wallpaper.this,arrayList,this);
        recyclerView.setAdapter(adapter);
        adapter.notifyDataSetChanged();


    @Override
    public void  recyclerViewListClicked(View v,int position){

        imageView.setImageResource(wallpaperImages[position]);

    }

ρ
ρяσѕρєя K

为您 RecyclerView 访问 rowLayout(cell)mainView 并在您的 OnBindViewHolder 中编写以下代码:

    @Override
    public void onBindViewHolder(MyViewHolder holder, final int position) {
        Movie movie = moviesList.get(position);
        holder.mainView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                System.out.println("pos " + position);
            }
        });
    }

T
That's Enam

它对我有用。希望它会有所帮助。最简单的方法。

内部视图架

class GeneralViewHolder extends RecyclerView.ViewHolder {
    View cachedView = null;

    public GeneralViewHolder(View itemView) {
        super(itemView);
        cachedView = itemView;
    }

OnBindViewHolder() 内部

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
            final GeneralViewHolder generalViewHolder = (GeneralViewHolder) holder;
            generalViewHolder.cachedView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context, "item Clicked at "+position, Toast.LENGTH_SHORT).show();
                }
            });

让我知道,您对此解决方案有任何疑问吗?


您应该在 onCreateViewHolder 中设置 onClickListener 以获得更好的性能,但随后您需要使用 getAdapterPosition() 获取位置(并防范 -1
M
Manikanta

而不是在视图持有者内实现接口 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();
        }
    }

你认为在每个 onBind() 方法调用中创建一个新的 OnItemClickListener 对象是一个好方法吗?
好工作。效果很好!
R
Roman Marusyk

使用PlaceHolderView

@Layout(R.layout.item_view_1)
public class View1{

    @View(R.id.txt)
    public TextView txt;

    @Resolve
    public void onResolved() {
        txt.setText(String.valueOf(System.currentTimeMillis() / 1000));
    }

    @Click(R.id.btn)
    public void onClick(){
        txt.setText(String.valueOf(System.currentTimeMillis() / 1000));
    }
}

我喜欢这个解决方案,它看起来很整洁,并且与我目前使用的 Pertusin 库完全一致。
d
dileep krishnan
 main_recyclerview.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
        @Override
        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
        {
            int position=rv.getChildAdapterPosition(rv.findChildViewUnder(e.getX(),e.getY()));

            switch (position)
            {
                case 0:
                {
                    wifi(position);
                    adapter2.notifyDataSetChanged();
                }
                break;

                case 1:
                {
                    sound(position);
                    adapter2.notifyDataSetChanged();
                }
                break;

                case 2:
                {
                    bluetooth(position);
                    adapter2.notifyDataSetChanged();
                }
                break;


            }
            return true;
        }

        @Override
        public void onTouchEvent(RecyclerView rv, MotionEvent e)
        {

        }

        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

        }
    });

问题是“为什么 RecyclerView 没有 onItemClickListener()?”不是“如何在 RecyclerView 中实现 onItemClickListener()?” .
C
Chathura Jayanath

我写了一个库来处理 android recycler view item click 事件。您可以在 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
            }
        });

或处理项目长按,您可以使用

RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemLongClickListener(new RecycleClick.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClicked(RecyclerView recyclerView, int position, View v) {
                // YOUR CODE
                return true;
            }
        });

先生,我已经尝试过您的图书馆,但遇到了 maven 的问题?
王 能

recyclerview动画没测试过,其他都正常。我认为它已被优化到最大。接口还有其他用途,可以暂时忽略。

public abstract class BaseAdapterRV<VH extends BaseViewHolder> extends RecyclerView.Adapter<VH> implements AdapterInterface {
    public final String TAG = getClass().getSimpleName();

    protected final Activity mActivity;
    protected final LayoutInflater mInflater;
    protected ItemClickInterface<?, Integer> mListener;

    public BaseAdapterRV(Activity activity) {
        mActivity = activity;
        mInflater = LayoutInflater.from(mActivity);
    }

    @Override
    public final VH onCreateViewHolder(ViewGroup parent, int viewType) {
        return onCreateViewHolder(parent, viewType, mInflater);
    }

    @Override
    public final void onBindViewHolder(VH holder, int position) {
        holder.itemView.setTag(R.id.tag_view_click, position);
        //创建点击事件
        holder.itemView.setOnClickListener(mListener);
        holder.itemView.setOnLongClickListener(mListener);
        onBindVH(holder, position);
    }


    ///////////////////////////////////////////////////////////////////////////
    // 以下是增加的方法
    ///////////////////////////////////////////////////////////////////////////

    /**
     * 注意!涉及到notifyItemInserted刷新时立即获取position可能会不正确
     * 里面也有onItemLongClick
     */
    public void setOnItemClickListener(ItemClickInterface<?, Integer> listener) {
        mListener = listener;
        notifyDataSetChanged();
    }

    @NonNull
    protected abstract VH onCreateViewHolder(ViewGroup parent, int viewType, LayoutInflater inflater);

    protected abstract void onBindVH(VH holder, int position);

}

这是接口

/**
 * OnItemClickListener的接口
 * 见子类实现{@link OnItemClickListener}{@link OnItemItemClickListener}
 */
public interface ItemClickInterface<DATA1, DATA2> extends View.OnClickListener, View.OnLongClickListener {

    void onItemClick(DATA1 data1, DATA2 data2);

    boolean onItemLongClick(DATA1 data1, DATA2 data2);
}

这是一个抽象类

public abstract class OnItemClickListener<DATA> implements ItemClickInterface<View, DATA> {
    @Override
    public void onClick(View v) {
        onItemClick(v, (DATA) v.getTag(R.id.tag_view_click));
    }

    @Override
    public boolean onLongClick(View v) {
        return onItemLongClick(v, (DATA) v.getTag(R.id.tag_view_click));
    }

    @Override
    public boolean onItemLongClick(View view, DATA data) {
        return false;
    }
}

你只需要它

    mAdapter.setOnItemClickListener(new OnItemClickListener<Integer>() {
        @Override
        public void onItemClick(View view, Integer integer) {

        }

        @Override
        public boolean onItemLongClick(View view, Integer integer) {
            return true;
        }
    });

BaseViewHolder 作为 RecyclerView.ViewHolder
R.id.tag_view_click 需要你在 values 目录中声明
s
sanevys

我发现了使用 androidx 生命周期可变实时数据的最短方法之一

适配器:

private val onItemClickListener = MutableLiveData<YourAdapterItem>()


override fun onBindViewHolder(holder: GifsViewHolder, position: Int) {
    holder.itemView.setOnClickListener { onItemClickListener.value = gifs[position] }
}
fun getOnItemClickListener(): MutableLiveData<Gif> {
    return onItemClickListener
}

MainActivity 中的任何位置

    yourFancyAdapter.getOnItemClickListener().observe(this, Observer {
        println(it)
    })