recyclerView 的 setOnClickListener 不起作用
Posted
技术标签:
【中文标题】recyclerView 的 setOnClickListener 不起作用【英文标题】:setOnClickListener for recyclerView not working 【发布时间】:2017-07-25 09:02:33 【问题描述】:对于RecyclerView
如果没有任何项目,则点击RecyclerView
作品,
但如果它有项目点击RecyclerView
不起作用。
小心我的意思是点击RecyclerView
而不是RecyclerView
的项目
recyclerView.setOnClickListener(view -> Timber.d("recyclerView clicked"););
我如何设置RecyclerView
可点击,即使它上面有项目。
【问题讨论】:
你的意思是点击特定的回收站视图行?? @sumit,不,我的意思是 recyclerView 而不是它的 items 和 rows 。像我想在 recyclerView 上设置点击监听器的任何其他视图一样 @YBDevi ,其实是另一种观点,不过这样不行! 那么只有你可以使用 OnTouchListener,因为如果你点击回收站视图,它只会被视为项目点击。 【参考方案1】:尝试扩展RecyclerView
并覆盖onInterceptTouchEvent
。也让它总是返回 true。然后使用OnTouch
而不是OnClickListener
这是一些代码。
public class MyRecyclerView extends RecyclerView
public MyRecyclerView(Context context, @Nullable AttributeSet attrs)
super(context, attrs);
@Override
public boolean onInterceptTouchEvent(MotionEvent e)
return true;
Activity.class
recyclerView.setOnTouchListener(new View.OnTouchListener()
@Override
public boolean onTouch(View v, MotionEvent event)
Toast.makeText(MainActivity.this,"RecyclerView",Toast.LENGTH_SHORT).show();
return false;
);
【讨论】:
是的,谢谢,我认为这可行,但我正在寻找另一种解决方案【参考方案2】:TL;DR Java
recyclerView.setOnTouchListener(new OnTouchListener()
@Override
public boolean onTouch(View view, MotionEvent motionEvent)
if (motionEvent.getAction() == MotionEvent.ACTION_UP)
return view.performClick();
else
return false;
);
recyclerView.setOnClickListener(new OnClickListener()
@Override
public void onClick(View view)
// do something
);
TL;DR Kotlin
recyclerView.setOnTouchListener view, motionEvent ->
if (motionEvent.action == MotionEvent.ACTION_UP)
view.performClick()
else
false
recyclerView.setOnClickListener view ->
// do something
说明(Java)
当用户触摸屏幕时,触发最顶层视图的OnTouchListener
。其目的是检测手势(点击、长按、滑动等)并调用相应的处理程序。例如,一个简单的点击应该会导致调用OnClickListener
。
现在,出于某种原因,RecyclerView
不这样做(至少它不注意点击手势)- 可能是因为开发人员不打算将 RecyclerView
作为一个整体点击。
所以,我们自己实现了OnTouchListener
。最简单的方法是在 OnTouchListener
本身中实现点击逻辑并返回 true
以防止事件在视图层次结构中进一步向上传播:
recyclerView.setOnTouchListener(new OnTouchListener()
@Override
public boolean onTouch(View view, MotionEvent motionEvent)
// do something
return true
);
但是,由于OnTouchListener
通常在单击屏幕时会被多次调用,因此我们应该在最后一次触摸事件之后只运行一次代码。此外,业务逻辑应该进入performClick()
调用的OnClickListener
(之后返回true
):
recyclerView.setOnTouchListener(new OnTouchListener()
@Override
public boolean onTouch(View view, MotionEvent motionEvent)
if (motionEvent.getAction() == MotionEvent.ACTION_UP)
return view.performClick();
else
return false;
);
recyclerView.setOnClickListener(new OnClickListener()
@Override
public void onClick(View view)
// do something
);
【讨论】:
【参考方案3】:只需使用setOnTouchListener
而不是setOnClickListener
。
它对我有用。 . .
recyclerView.setOnTouchListener(new View.OnTouchListener()
@Override
public boolean onTouch(View view, MotionEvent motionEvent)
//Do anyThing you need
return false;
);
【讨论】:
这个解决方案的有趣之处在于 MotionEvent.ACTION_DOWN 永远不会被调用,因此如果发生 ACTION_MOVE 事件就会调用 ACTION_UP【参考方案4】:但如果有项目点击 RecyclerView 不起作用
为什么您认为您正在点击RecyclerView
本身?
很可能RecyclerView
的项目吞下了触摸事件,因此它不会到达RecyclerView
。您可以使RecyclerView
的子项不可点击,那么下一个有机会响应点击事件的项目将是RecyclerView
。
【讨论】:
尝试为项目 xml 设置可点击和可聚焦的 false,但它没有帮助向 RecyclerView 提供点击事件以作为视图执行。【参考方案5】:您首先需要一个指定侦听器行为的接口。在此示例中,有一个名为 ContentItem 的示例模型,因此单击将返回该类型的项目:
public interface OnItemClickListener
void onItemClick(ContentItem item);
构造函数将接收一个实现此接口的对象,以及要渲染的项目:
私有最终列表项; 私有最终 OnItemClickListener 监听器;
public ContentAdapter(List<ContentItem> items, OnItemClickListener listener)
this.items = items;
this.listener = listener;
您也可以创建一个 setOnItemClickListener 方法并以这种方式分配它。现在,在 onBindViewHolder 中,ViewHolder 将在自定义绑定方法中接收构造函数:
@Override public void onBindViewHolder(ViewHolder holder, int position)
holder.bind(items.get(position), listener);
这就是这个绑定方法的样子:
public void bind(final ContentItem item, final OnItemClickListener listener)
...
itemView.setOnClickListener(new View.OnClickListener()
@Override public void onClick(View v)
listener.onItemClick(item);
);
通过创建一个新的适配器和侦听器来在您需要时使用它,以在单击项目时实现该行为。一个简单的例子:
recycler.setAdapter(new ContentAdapter(items, new ContentAdapter.OnItemClickListener()
@Override public void onItemClick(ContentItem item)
Toast.makeText(getContext(), "Item Clicked", Toast.LENGTH_LONG).show();
));
【讨论】:
@MehrdadFaraji android 不会给你 onItemClick 和列表视图控件一样的,你必须手动实现。【参考方案6】:因为还没有人回答实际问题本身..
我的解决方案是使用 ConstraintLayout 在 RecyclerView 顶部放置一个空视图,例如
<androidx.recyclerview.widget.RecyclerView
app:layout_constraintTop_toBottomOf="@+id/toolbar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:id="@+id/recycler_view"
android:layout_
android:layout_>
</androidx.recyclerview.widget.RecyclerView>
<View
android:id="@+id/touch_overlay"
android:layout_
android:layout_
app:layout_constraintTop_toTopOf="@+id/recycler_view"
app:layout_constraintStart_toStartOf="@+id/recycler_view"
app:layout_constraintEnd_toEndOf="@+id/recycler_view"
app:layout_constraintBottom_toBottomOf="@+id/recycler_view"/>
然后我会在 touch_overlay 上设置 onClickListener,它会按预期工作。
在 Java/Kotlin 方面正如预期的那样
binding.touchOverlay.setOnClickListener
Toast.makeText(context, "clicked recyclerView", Toast.LENGTH_LONG).show()
另一方面,更轻量级的解决方案,尤其是在不使用 ConstraintLayout 时,是使用 FrameLayout,然后在 RecyclerView 顶部放置一个空 View 以接收点击
【讨论】:
【参考方案7】:此代码有效:
recycle.setOnTouchListener v, event ->
if(event.action == MotionEvent.ACTION_UP)
onClickListener.onClick(v)
false
【讨论】:
以上是关于recyclerView 的 setOnClickListener 不起作用的主要内容,如果未能解决你的问题,请参考以下文章