我有一个带有2个项目的RecyclerView,它们不会填满整个屏幕。如何检测到用户点击了RecyclerView的空白部分(意味着直接点击了RecyclerView而不是其中一个项目)?
答案 0 :(得分:14)
如评论中所述
mRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
if (motionEvent.getAction() != MotionEvent.ACTION_UP) {
return false;
}
View child = recyclerView.findChildViewUnder(motionEvent.getX(), motionEvent.getY());
if (child != null) {
// tapped on child
return false;
} else {
// Tap occured outside all child-views.
// do something
return true;
}
}
@Override
public void onTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
}
});
答案 1 :(得分:11)
您可以继承RecyclerView
并覆盖dispatchTouchEvent()
方法来完成此操作。使用findChildViewUnder()
方法,我们可以确定触摸事件是否发生在子视图之外,并使用interface
通知侦听器是否存在。在以下示例中,OnNoChildClickListener
interface
提供了该功能。
public class TouchyRecyclerView extends RecyclerView
{
// Depending on how you're creating this View,
// you might need to specify additional constructors.
public TouchyRecyclerView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
private OnNoChildClickListener listener;
public interface OnNoChildClickListener
{
public void onNoChildClick();
}
public void setOnNoChildClickListener(OnNoChildClickListener listener)
{
this.listener = listener;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event)
{
// The findChildViewUnder() method returns null if the touch event
// occurs outside of a child View.
// Change the MotionEvent action as needed. Here we use ACTION_DOWN
// as a simple, naive indication of a click.
if (event.getAction() == MotionEvent.ACTION_DOWN
&& findChildViewUnder(event.getX(), event.getY()) == null)
{
if (listener != null)
{
listener.onNoChildClick();
}
}
return super.dispatchTouchEvent(event);
}
}
注意:这适用于RecyclerView
GridView
关于{{1}}。{/ p>
答案 2 :(得分:4)
@ driss-bounouar的回答几乎是正确的,但这会阻止用户滚动回收者视图,因为任何向下事件都会导致您的操作发生。稍微修改我们记录向下事件,然后检查up事件,如果坐标没有太大变化,则触发事件。
private MotionEvent lastRecyclerViewDownTouchEvent;
myRecyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN && myRecyclerView.findChildViewUnder(event.getX(), event.getY()) == null) {
lastRecyclerViewDownTouchEvent = event;
} else if (event.getAction() == MotionEvent.ACTION_UP && myRecyclerView.findChildViewUnder(event.getX(), event.getY()) == null
&& lastRecyclerViewDownTouchEvent != null) {
// Check to see if it was a tap or a swipe
float xDelta = Math.abs(lastRecyclerViewDownTouchEvent.getX() - event.getX());
float yDelta = Math.abs(lastRecyclerViewDownTouchEvent.getY() - event.getY());
if (xDelta < 30 && yDelta < 30) {
// Do action
}
lastRecyclerViewDownTouchEvent = null;
}
return false;
}
});
答案 3 :(得分:1)
您只需在上面显示的TouchListener
上设置RecyclerView
:
categoryTable.setAdapter(new CatgoriesAdapter(categories.getWrappedList()));
categoryTable.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN
&& categoryTable.findChildViewUnder(event.getX(), event.getY()) == null)
{
// Touch outside items here, you do whatever you want
HideCategoryMenu();
}
return false;
}
});
答案 4 :(得分:1)
这对我有用,我用它来代替 RecyclerView:
public class ClickeableRecyclerView extends RecyclerView
{
private static final int CLICK_DURATION = 800;
private CountDownTimer clickCountDown;
private final Object sincClick = new Object();
private boolean shortClick = true;
public ClickeableRecyclerView(@NonNull Context context)
{
super(context);
init();
}
public ClickeableRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs)
{
super(context, attrs);
init();
}
public ClickeableRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
init();
}
private void init()
{
clickCountDown = new CountDownTimer(CLICK_DURATION, 100)
{
public void onTick(long millisUntilFinished)
{
synchronized(sincClick)
{
shortClick = true;
}
}
public void onFinish()
{
synchronized(sincClick)
{
shortClick = false;
}
}
};
}
@Override
public boolean onTouchEvent(MotionEvent e)
{
if(findChildViewUnder(e.getX(), e.getY()) == null)
{
if(e.getAction() == MotionEvent.ACTION_DOWN)
{
clickCountDown.start();
}
else if(e.getAction() == MotionEvent.ACTION_UP)
{
synchronized(sincClick)
{
if(shortClick)
{
performClick();
clickCountDown.cancel();
}
}
}
}
else
{
clickCountDown.cancel();
}
return super.onTouchEvent(e);
}
@Override
public boolean performClick()
{
return super.performClick();
}
}
在布局中:
<yourpackage.ClickeableRecyclerView
android:id="@+id/recyclerViewItems"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@color/white"
android:visibility="visible"
app:layout_constraintBottom_toTopOf="@+id/viewTotal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/buttonShowItems"
tools:visibility="visible" />
在活动中:
private ClickeableRecyclerView recyclerView;
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
// Do something when click no items
}
});
希望能帮到你。
答案 5 :(得分:0)
shortcutDeviceRecly.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP){
roomClickEvent(true, v);
}
return false;
}
});
答案 6 :(得分:0)
@Angel Kjoseski的答案在科特林看起来像这样:
yourRecyclerView.addOnItemTouchListener(object : RecyclerView.OnItemTouchListener {
override fun onInterceptTouchEvent(recyclerView: RecyclerView, motionEvent: MotionEvent): Boolean {
return when {
motionEvent.action != MotionEvent.ACTION_UP || recyclerView.findChildViewUnder(motionEvent.x, motionEvent.y) != null -> false
else -> {
// do something here
true
}
}
}
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
override fun onTouchEvent(recyclerView: RecyclerView, motionEvent: MotionEvent) {}
})