【发布时间】:2014-12-30 10:31:24
【问题描述】:
我有一个 RecyclerView,其中有 2 个项目没有填满整个屏幕。如何检测到用户点击了 RecyclerView 的空白部分(意味着直接点击了 RecyclerView 而不是其中一项)?
【问题讨论】:
标签: android android-recyclerview
我有一个 RecyclerView,其中有 2 个项目没有填满整个屏幕。如何检测到用户点击了 RecyclerView 的空白部分(意味着直接点击了 RecyclerView 而不是其中一项)?
【问题讨论】:
标签: android android-recyclerview
如评论中所述
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) {
}
});
【讨论】:
return false;,而不是MotionEvent.ACTION_UP 部分下的return;。
true 之前调用 mRecyclerView.playSoundEffect(SoundEffectConstants.CLICK); 来解决。
您可以继承 RecyclerView 并覆盖 dispatchTouchEvent() 方法来完成此操作。使用findChildViewUnder() 方法,我们可以确定触摸事件是否发生在子View 之外,如果是,则使用interface 通知侦听器。在以下示例中,OnNoChildClickListenerinterface 提供了该功能。
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 来自 my answer here 与 GridView 相关的内容。
【讨论】:
@driss-bounouar 的回答几乎是正确的,尽管这会阻止用户滚动回收站视图,因为任何向下事件都会导致您的操作发生。稍作修改,我们记录下事件,然后检查上事件,如果坐标没有太大变化,然后触发事件。
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;
}
});
【讨论】:
您只需要在RecyclerView 上设置一个TouchListener,如上所示:
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;
}
});
【讨论】:
@Angel Kjosski 的答案在 Kotlin 中看起来像这样:
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) {}
})
【讨论】:
这对我有用,我用它来代替 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
}
});
希望对你有帮助。
【讨论】:
shortcutDeviceRecly.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP){
roomClickEvent(true, v);
}
return false;
}
});
【讨论】: