2014-12-30 1 views
7

Ho un RecyclerView con 2 elementi che non riempiono l'intero schermo. Come posso rilevare che l'utente ha fatto clic sulla parte vuota di RecyclerView (che significa che è stato fatto clic direttamente su RecyclerView e non su uno dei suoi elementi)?Rileva clic su RecyclerView al di fuori degli articoli

risposta

4

È possibile creare una sottoclasse di RecyclerView e sovrascrivere il metodo dispatchTouchEvent() per ottenere ciò. Usando il metodo findChildViewUnder(), possiamo determinare se un evento tattile si verifica al di fuori delle viste secondarie e utilizzare un interface per notificare un listener, se lo è. Nell'esempio seguente, OnNoChildClickListenerinterface fornisce tale funzionalità.

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: Questo è adattato per RecyclerView da my answer here relativa GridView.

+1

Grazie mille! Ho finito per usare recyclerView.addOnItemTouchListener con findChildViewUnder (..). – Omar

+0

@Omar Ah! Molto bene! Mi sto ancora familiarizzando con RecyclerView e non ero ancora a conoscenza di quell'interfaccia. Grazie per le informazioni! Dovresti creare una risposta per questo. Riceverai un preventivo da me. –

7

Come accennato nel commento

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

Dovrebbe anche controllare MotionEvent.getAction() == ACTION_UP, altrimenti, si ottengono 2 eventi click. –

+0

Grazie @ greg-ennis. Ho aggiornato il codice. –

+0

Questa dovrebbe essere la risposta accettata. Inoltre dovrebbe probabilmente essere 'return false;' piuttosto che 'return;' sotto la parte 'MotionEvent.ACTION_UP'. –

1

Hai solo bisogno di impostare un TouchListener sul RecyclerView come mostrato sopra:

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

@ risposta di Driss-Bounouar è ​​quasi giusto anche se questo impedirà il l'utente dallo scorrimento della vista del riciclatore come qualsiasi evento inatteso causerà l'azione. Con una leggera modifica in cui registriamo l'evento down e quindi controlliamo l'evento up se le coordinate non sono cambiate molto, quindi attivate l'evento.

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