Обнаружить нажмите "RecyclerView" за пределами элементов

У меня есть RecyclerView с двумя элементами, которые не заполняют весь экран. Как я могу обнаружить, что пользователь нажал на пустую часть RecyclerView (что означает, что нажатие непосредственно на RecyclerView, а не на один из его элементов)?

Ответ 1

Вы можете подклассифицировать 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);
    }
}

NB: Это адаптировано для RecyclerView от моего ответа здесь относительно GridView.

Ответ 2

Как упоминалось в комментарии

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) {
  }
});

Ответ 3

@Ответ на driss-bounouar почти прав, хотя это не позволит пользователю прокручивать просмотр recycler, поскольку любое событие down приведет к вашему действию. С небольшим изменением, где мы записываем событие вниз, а затем проверяем событие "вверх", если координаты не сильно изменились, затем запустите событие.

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;
                    }
                });

Ответ 4

Вам просто нужно установить 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;
        }
    });

Ответ 5

shortcutDeviceRecly.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {

                if(event.getAction() == MotionEvent.ACTION_UP){
                    roomClickEvent(true, v);
                }

                return false;
            }
        });