android - onitemtouchlistener - onlongclicklistener recyclerview
Recyclerview interno no recibe el evento click (1)
Así que después de aproximadamente un día tratando de resolver esto, finalmente logré resolver este problema.
Después de haber realizado todos estos pasos, debe terminar con:
- Una vista externa del reciclador que no se ve obstaculizada por los eventos de desplazamiento de una vista interior del reciclador, que se desplaza en la vista interior del reciclador, está desactivada. Esto es útil en el escenario cuando desea utilizar el enfoque de la barra de herramientas colapsada con la vista recicladora externa e interna.
- Se puede hacer clic en los elementos en la vista interna del reciclador (de qué sirve una vista interior del reciclador que muestra una lista de elementos si no se puede hacer clic en ellos).
En primer lugar, vi algunos videos sobre el tema del tacto en Android: https://www.youtube.com/watch?v=SYoN-OvdZ3M&list=PLonJJ3BVjZW6CtAMbJz1XD8ELUs1KXaTD&index=19
Obtuve el enlace del video desde aquí: Android: ¿diferencia entre onInterceptTouchEvent y dispatchTouchEvent?
Ahora, tuve que personalizar mi onDispatchTouchEvent:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
final int actionMasked = action & MotionEvent.ACTION_MASK;
Log.e("actionmasked", "" + actionMasked);
switch (actionMasked) {
case MotionEvent.ACTION_DOWN:
return super.dispatchTouchEvent(ev);
case MotionEvent.ACTION_MOVE:
return true;
case MotionEvent.ACTION_CANCEL:
return true;
case MotionEvent.ACTION_UP:
return super.dispatchTouchEvent(ev);
default:
return super.dispatchTouchEvent(ev);
}
He llamado a super.dispatchTouchEvent (ev) tanto en ABAJO como ARRIBA y en los casos predeterminados, ya que queremos que el hijo de la recicladora interna maneje esos eventos. El evento debe ir desde viewgroup, que es esta vista recicladora personalizada (ScrollThroughRecyclerView) a las vistas dentro de la vista recycler.
Para MOVE y CANCEL, devolvemos true para decir que la vista interior del reciclador manejó esos eventos y que el evento puede regresar al padre, lo que permitirá que la vista exterior del reciclador se desplace correctamente. Esto no obstaculizará el comportamiento de la aplicación de la barra de herramientas colapsada.
Ahora necesitamos un método personalizado onInterceptTouchEvent:
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
final int action = e.getAction();
final int actionMasked = action & MotionEvent.ACTION_MASK;
if (actionMasked == MotionEvent.ACTION_DOWN) {
return false; //intercepted by the viewgroup and passed down to child
} else if (actionMasked == MotionEvent.ACTION_UP) {
return false; //intercepted by the viewgroup and passed down to child
}
return super.onInterceptTouchEvent(e);
}
Tanto para ARRIBA como ABAJO, devolvemos el valor falso ya que queremos que el niño que se encuentra dentro de la recicladora interna maneje esos eventos (desde ARRIBA y ABAJO, podemos determinar en qué elemento de la vista del reciclador realmente se hizo clic).
Para todo lo demás, usamos el comportamiento predeterminado, así que he llamado: super.onInterceptTouchEvent (e)
Ahora en el adaptador de recyclerview:
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof PostViewHolder) {
((PostViewHolder) holder).rl.setOnTouchListener(onTouchListener);
}
Establezca un touchlistener en la vista que está escuchando para evento táctil en su vista de reciclador. Para mí, dado que estoy escuchando los clics en toda la línea de la vista del reciclador, configuré el oyente táctil en rl, que representa la duración relativa de la línea que se muestra en la vista del reciclador.
El asistente de toque no recibirá los motivos DOWN y UP que el grupo de vista pasó en el método onInterceptTouchEvent.
Como solo tenemos DOWN y UP Motionevent, detectar clics puede ser un poco más tedioso que la forma general de decir setOnClickListener. Además, como está utilizando Touch, el Touch realmente anula el OnClickListener y no se invoca nada enClickListener. Para detectar los clics en el artículo en la vista de reciclador a través de onTouchListener, necesitará este método:
View.OnTouchListener onTouchListener = new View.OnTouchListener() {
private float startX;
private float startY;
private static final int CLICK_ACTION_THRESHHOLD = 5;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
break;
case MotionEvent.ACTION_UP: {
float endX = event.getX();
float endY = event.getY();
if (isAClick(startX, endX, startY, endY)) {
Log.e("UserClick", "user has clicked");// WE HAVE A CLICK!!
}
break;
}
default:
return true;
}
return true;
}
private boolean isAClick(float startX, float endX, float startY, float endY) {
float differenceX = Math.abs(startX - endX);
float differenceY = Math.abs(startY - endY);
if (differenceX > CLICK_ACTION_THRESHHOLD || differenceY > CLICK_ACTION_THRESHHOLD) {
return false;
}
return true;
}
};
Tengo una vista de reciclaje de padres con tarjetas llenas y una vista interior de reciclador dentro de cada tarjeta.
Se ha deshabilitado el desplazamiento para la vista de reciclador interno dentro de las tarjetas, pero esto también ha afectado la capacidad de la vista interna del reciclador para recibir eventos de clic.
Para desactivar el desplazamiento, había seguido una respuesta muy similar a la de Lucas Crawford, que sugería que crease una clase de reciclador personalizada y reemplazara a dispatchTouchEvent: Disable Scrolling in child Recyclerview android
Mi clase se ve así:
public class ScrollThroughRecyclerView extends RecyclerView {
private boolean isOnClick;
public ScrollThroughRecyclerView(Context context) {
super(context);
}
public ScrollThroughRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScrollThroughRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
final int actionMasked = action & MotionEvent.ACTION_MASK;
Log.e("actionmasked", "" + actionMasked);
switch (actionMasked) {
case MotionEvent.ACTION_DOWN:
Log.e("motionDown", "onclick: "+isOnClick);
isOnClick = true;
break;
case MotionEvent.ACTION_MOVE:
isOnClick = false;
Log.e("motionMove", "onclick: "+isOnClick);
return true;
case MotionEvent.ACTION_UP:
Log.e("motionUp", "onclick: "+isOnClick);
if (isOnClick) {
return super.dispatchTouchEvent(ev);
}
break;
default:
return true;
}
return true;
}
Sin embargo, nunca registra los eventos de clic, pero el desplazamiento está deshabilitado correctamente.
¿Cómo puedo obtener la vista interna del reciclador para registrar los eventos de clic?