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
È 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, OnNoChildClickListener
interface
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
.
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) {
}
});
Dovrebbe anche controllare MotionEvent.getAction() == ACTION_UP, altrimenti, si ottengono 2 eventi click. –
Grazie @ greg-ennis. Ho aggiornato il codice. –
Questa dovrebbe essere la risposta accettata. Inoltre dovrebbe probabilmente essere 'return false;' piuttosto che 'return;' sotto la parte 'MotionEvent.ACTION_UP'. –
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;
}
});
@ 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;
}
});
Grazie mille! Ho finito per usare recyclerView.addOnItemTouchListener con findChildViewUnder (..). – Omar
@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. –