首页 > Java > 为什么 RecyclerView 没有 onItemClickListener()?

为什么 RecyclerView 没有 onItemClickListener()?

上一篇 下一篇

我正在探索,我很惊讶地发现没有.RecyclerViewRecyclerViewonItemClickListener()

我有两个问题。

主要问题

我想知道为什么谷歌删除了?onItemClickListener()

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

次要问题

我通过写我的 :onClickRecyclerView.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

这是一个工具箱,与旧的相比,它具有更少的内置功能和更大的灵活性。这不是从列表视图中删除的唯一功能。但是它有很多听众和方法可以根据您的喜好扩展它,它在正确的手中;)要强大得多。RecyclerViewListViewonItemClickListener

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

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

内存效率 – 适用于 onItemClickListener 的插入式解决方案

这个解决方案是由Android GDE的Hugo Visser提出的,在发布之后。他提供了一个免许可证课程,供您输入代码并使用它。RecyclerView

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

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

Kotlin / 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 版本的奖励功能

有时,您不希望回收器视图的所有项目都是可单击的。

为了解决这个问题,我介绍了一个界面,你可以在你的上面使用它来控制哪个项目是可点击的。ItemClickSupportViewHolderViewHolder

例:

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.OnChildAttachStateChangeListenerRecyclerViewRecyclerViewRecyclerViewRecyclerView.ViewHolder

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

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

结语

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

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

它也有点反对关注点分离,因为它并不是适配器委派单击事件的真正工作。
分割线
网友回答:

2016年博士使用 RxJava 和 PublishSubject 为点击公开可观察量。

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

原文:

自引入以来,一直存在问题。一旦您拥有任何内部元素的点击侦听器,就不会触发回调,但它没有收到通知或详细记录(如果有的话),因此有很多困惑和 SO 问题。ListViewonItemClickListener

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

不要将它视为 1:1 的替换,而是将其视为用于复杂用例的更灵活的组件。正如你所说,你的解决方案是谷歌对你的期望。现在,您有一个适配器,它可以将 onClick 委托给在构造函数上传递的接口,这是 和 的正确模式。RecyclerviewListViewListViewRecyclerview

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
分割线
网友回答:

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

里面

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

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

模板简介:该模板名称为【为什么 RecyclerView 没有 onItemClickListener()?】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【Java】栏目查找您需要的精美模板。

相关搜索
  • 下载密码 lanrenmb
  • 下载次数 206次
  • 使用软件 Sublime/Dreamweaver/HBuilder
  • 文件格式 编程语言
  • 文件大小 暂无信息
  • 上传时间 03-03
  • 作者 网友投稿
  • 肖像权 人物画像及字体仅供参考
栏目分类 更多 >
热门推荐 更多 >
html5 自适应 微信模板 微信图片 微信素材 单页式简历模板 微信公众平台 响应式 企业网站 微信文章
您可能会喜欢的其他模板