recyclerView 的 setOnClickListener 不起作用
setOnClickListener for recyclerView not working
对于RecyclerView
如果没有任何项目,则点击RecyclerView
作品,
但是如果它有项目点击 RecyclerView
不起作用。
请注意,我的意思是只点击 RecyclerView
而不是 RecyclerView
的项目
recyclerView.setOnClickListener(view -> {Timber.d("recyclerView clicked");});
如何设置 RecyclerView
可点击,即使上面有项目。
but if it has items clicking on RecyclerView doesn't work
您认为您为什么要对 RecyclerView
本身执行点击?
很可能 RecyclerView
的项目吞噬了触摸事件,因此它不会到达 RecyclerView
。您可以使 RecyclerView
的子项不可点击,那么下一个有机会响应点击事件的项目将是 RecyclerView
.
您首先需要一个接口来指定侦听器的行为。在此示例中,有一个名为 ContentItem 的示例模型,因此单击将 return 一个该类型的项目:
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();
}
}));
尝试扩展 RecyclerView
并覆盖 onInterceptTouchEvent
。也让它总是 return 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;
}
});
因为还没有人回答实际问题本身..
我的解决方案是在带有 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_width="match_parent"
android:layout_height="0dp">
</androidx.recyclerview.widget.RecyclerView>
<View
android:id="@+id/touch_overlay"
android:layout_width="0dp"
android:layout_height="0dp"
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 顶部放置一个空视图,以接收点击
只需使用 setOnTouchListener
而不是 setOnClickListener
。
对我有用。 . .
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
//Do anyThing you need
return false;
}
});
此代码有效:
recycle.setOnTouchListener { v, event ->
if(event.action == MotionEvent.ACTION_UP){
onClickListener.onClick(v)
}
false
}
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
本身和 return true
中实现点击逻辑,以防止事件在视图层次结构中向上传播:
recyclerView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
// do something
return true
}
});
但是,由于 OnTouchListener
通常会在单击屏幕时多次调用,因此我们应该 运行 我们的代码仅在最后一次触摸事件后调用一次。此外,业务逻辑应该进入 performClick()
调用的 OnClickListener
(之后 returns 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
}
});
对于RecyclerView
如果没有任何项目,则点击RecyclerView
作品,
但是如果它有项目点击 RecyclerView
不起作用。
请注意,我的意思是只点击 RecyclerView
而不是 RecyclerView
的项目
recyclerView.setOnClickListener(view -> {Timber.d("recyclerView clicked");});
如何设置 RecyclerView
可点击,即使上面有项目。
but if it has items clicking on RecyclerView doesn't work
您认为您为什么要对 RecyclerView
本身执行点击?
很可能 RecyclerView
的项目吞噬了触摸事件,因此它不会到达 RecyclerView
。您可以使 RecyclerView
的子项不可点击,那么下一个有机会响应点击事件的项目将是 RecyclerView
.
您首先需要一个接口来指定侦听器的行为。在此示例中,有一个名为 ContentItem 的示例模型,因此单击将 return 一个该类型的项目:
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();
}
}));
尝试扩展 RecyclerView
并覆盖 onInterceptTouchEvent
。也让它总是 return 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;
}
});
因为还没有人回答实际问题本身..
我的解决方案是在带有 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_width="match_parent"
android:layout_height="0dp">
</androidx.recyclerview.widget.RecyclerView>
<View
android:id="@+id/touch_overlay"
android:layout_width="0dp"
android:layout_height="0dp"
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 顶部放置一个空视图,以接收点击
只需使用 setOnTouchListener
而不是 setOnClickListener
。
对我有用。 . .
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
//Do anyThing you need
return false;
}
});
此代码有效:
recycle.setOnTouchListener { v, event ->
if(event.action == MotionEvent.ACTION_UP){
onClickListener.onClick(v)
}
false
}
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
本身和 return true
中实现点击逻辑,以防止事件在视图层次结构中向上传播:
recyclerView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
// do something
return true
}
});
但是,由于 OnTouchListener
通常会在单击屏幕时多次调用,因此我们应该 运行 我们的代码仅在最后一次触摸事件后调用一次。此外,业务逻辑应该进入 performClick()
调用的 OnClickListener
(之后 returns 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
}
});