我正在探索,我很惊讶地发现没有.RecyclerView
RecyclerView
onItemClickListener()
我有两个问题。
我想知道为什么谷歌删除了?onItemClickListener()
是否存在性能问题或其他问题?
我通过写我的 :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
这是一个工具箱,与旧的相比,它具有更少的内置功能和更大的灵活性。这不是从列表视图中删除的唯一功能。但是它有很多听众和方法可以根据您的喜好扩展它,它在正确的手中;)要强大得多。RecyclerView
ListView
onItemClickListener
在我看来,删除的最复杂的功能是快速滚动。大多数其他功能都可以轻松重新实现。RecyclerView
如果您想知道还添加了哪些其他很酷的功能,请阅读另一个问题的答案。RecyclerView
这个解决方案是由Android GDE的Hugo Visser提出的,在发布之后。他提供了一个免许可证课程,供您输入代码并使用它。RecyclerView
它展示了通过使用 引入的一些多功能性。RecyclerView
RecyclerView.OnChildAttachStateChangeListener
编辑 2019:我的 kotlin 版本,java one,来自 Hugo Visser,保留在下面
创建一个文件并将其放入其中: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文件,请参阅本节上方)
有时,您不希望回收器视图的所有项目都是可单击的。
为了解决这个问题,我介绍了一个界面,你可以在你的上面使用它来控制哪个项目是可点击的。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
如果需要更多,您还可以调整代码以将持有者本身还给您。
请记住,通过在列表的每个视图上设置单击侦听器来处理它是完全可以的,就像提出的其他答案一样。
这不是最有效的做法(每次重用视图时都会创建一个新的侦听器),但它有效,并且在大多数情况下这不是问题。
它也有点反对关注点分离,因为它并不是适配器委派单击事件的真正工作。
网友回答:
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 问题。ListView
onItemClickListener
鉴于这更进一步,并且没有行/列的概念,而是任意布局的子项数量,他们将onClick委托给每个人或程序员实现。RecyclerView
不要将它视为 1:1 的替换,而是将其视为用于复杂用例的更灵活的组件。正如你所说,你的解决方案是谷歌对你的期望。现在,您有一个适配器,它可以将 onClick 委托给在构造函数上传递的接口,这是 和 的正确模式。Recyclerview
ListView
ListView
Recyclerview
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】栏目查找您需要的精美模板。