android android-recyclerview ontouchevent smooth-scrolling

android - Evitar que RecyclerView consuma eventos táctiles



android-recyclerview ontouchevent (1)

En primer lugar, debe definir un OnItemTouchListener, tal vez como una variable global como esta:

RecyclerView.OnItemTouchListener mOnItemTouchListener = new RecyclerView.OnItemTouchListener() { @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { if (e.getAction() == MotionEvent.ACTION_DOWN && rv.getScrollState() == RecyclerView.SCROLL_STATE_SETTLING) { Log.d(TAG, "onInterceptTouchEvent: click performed"); rv.findChildViewUnder(e.getX(), e.getY()).performClick(); return true; } return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) {} @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {} };

¿Por qué ACTION_DOWN y SCROLL_STATE_SETTLING?

El evento de movimiento ACTION_DOWN se activará cuando toque RecyclerView, y en ese momento exacto RecyclerView cambia su estado de desplazamiento a SCROLL_STATE_SETTLING mientras intenta detener el desplazamiento. Y eso es exactamente cuando desea realizar el clic.

Y recuerde que es verdadero para decirle a su RecyclerView que ha consumido MotionEvent. De lo contrario, su performClick () podría ser llamado más de una vez.

Agrégalo a tu RecyclerView en onResume y quítalo en onPause, y ya estás listo;)

ACTUALIZAR

Agregue un null checker cuando esté haciendo findChildViewUnder - devuelve null cuando no está tocando una celda específica.

View childView = rv.findChildViewUnder(e.getX(), e.getY()); if (childView != null) childView.performClick();

ACTUALIZACIÓN 2

Resulta que detener el RecyclerView de desplazamiento sería suficiente. Haz esto en su lugar:

@Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { if (e.getAction() == MotionEvent.ACTION_DOWN && rv.getScrollState() == RecyclerView.SCROLL_STATE_SETTLING) rv.stopScroll(); return false; }

Problema

Estoy intentando simular el comportamiento exacto de la aplicación Google Play.

Actualmente, cuando está desplazándose por una categoría como "Juegos principales" y toca la lista, esa celda y RecyclerView manejan el evento táctil, puede ver que ambos lo están manejando debido a la ondulación que aparece cuando sostiene el dedo abajo, así como el desplazamiento que se detiene. O si hace clic en una celda mientras la lista todavía se está moviendo, ese contenido se abre de inmediato.

El comportamiento predeterminado es que el desplazamiento se detenga instantáneamente si coloca el dedo hacia abajo mientras se mueve, y luego consume ese evento táctil, lo que significa que nunca se le informa a la célula acerca de ese toque. Esto es increíblemente irritante cuando el contenido principal de su aplicación está en un RecyclerView y si el usuario se desplaza continuamente y luego hace clic en una celda, requiere que haga clic dos veces, ya que el primer clic se ha detenido al detener el desplazamiento, incluso si la lista apenas moviéndose.

Lo que he intentado hasta ahora

Al principio, pensé que debía haber algún tipo de bandera dentro de RecyclerView que RecyclerView que no consumiera el evento táctil. Revisé el código fuente de Android y enrute la documentación de Android sin ningún resultado.

Luego traté de capturar el evento táctil con onInterceptTouchEvent y le dije manualmente a mi punto de vista que se estaba tocando;

@Override public boolean onInterceptTouchEvent(MotionEvent event) { View myCell = recyclerView.findChildViewUnder(event.getX(), event.getY()); myCell.dispatchTouchEvent(event); return super.onInterceptTouchEvent(event); }

Aquí, dispatchTouchEvent no pareció hacer nada a pesar de que la vista que recibía tenía la etiqueta correspondiente que configuré en el adaptador.

Intenté fotografiar este problema con mi ametralladora de código en todos los ángulos; jugando con requestDisallowInterceptTouchEvent , llamando manualmente a onTouch y anulando todo tipo de oyentes para RecyclerView y más allá.

Nada parece estar funcionando. Estoy seguro de que debe haber una solución elegante para esto y he echado un vistazo a un detalle importante en algún punto del camino hacia la locura. Especialmente porque las propias aplicaciones de Google se comportan de esta manera.

¡Por favor ayuda! :) Gracias.

La solución

Gracias a Jagoan Neon se ha encontrado una solución. Terminé envolviendo su respuesta dentro de un RecyclerView personalizado para facilitar su uso.

public class MultiClickRecyclerView extends RecyclerView { public MultiClickRecyclerView(Context context) { super(context); } public MultiClickRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public MultiClickRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN && this.getScrollState() == RecyclerView.SCROLL_STATE_SETTLING) { this.stopScroll(); } return super.onInterceptTouchEvent(event); } }