Deje que la vista de los padres asumiera MotionEvents si el niño devuelve falso
-
27-10-2019 - |
Pregunta
Tengo una aplicación que necesita manejo de eventos de manera inusual.
Para mi pregunta, permítanme explicar primero un caso simple de que el sistema actual de manejo de eventos de Android no me queda bien.
Suponiendo que tengo un framelayout (que llamaré a Viewswiper desde ahora) que todas las vistas agregadas en él son Match_Parent X Match_parent (que llamaré PageView), maneja los eventos traduciendo la vista real y reemplazarla en función de la dirección de moverse. Este componente que ya he hecho y funcionando correctamente ( Uso de la animación para deslizar las vistas ).
Pero el problema está en esa vista de página que agrego encima, en el caso de ImageViews que devuelvan falsos en su OnTouchEvent, el ViewSwiper manejará los eventos y dejará que otro PageView ingrese a la pantalla, pero si agrego una vista de desplazamiento sobre eso, todo el Los eventos serán consumidos por el pergamino y el ViewSwiper no tendrá la oportunidad de reemplazar el PageView.
Así que descubrí que devolver el falso onuchevent de ScrollView, el padre puede asumir que son eventos, escribí esta subclase de ScrollView para probarlo:
public class ScrollViewVertical extends ScrollView {
public ScrollViewVertical(Context context) {
super(context);
setOverScrollMode(OVER_SCROLL_ALWAYS);
setVerticalScrollBarEnabled(false);
}
public boolean onTouchEvent(MotionEvent evt) {
super.onTouchEvent(evt);
return false;
}
}
Pero devolverse False haz más eventos para ser enviados a los padres, pero necesito estos eventos para desplazamiento vertical, por lo que tengo la idea de devolver falses solo si el usuario se mueve horizontal, así es como se ve mi código:
public class ScrollViewVertical extends ScrollView {
private MovementTracker moveTracker;
public ScrollViewVertical(Context context) {
super(context);
setOverScrollMode(OVER_SCROLL_ALWAYS);
setVerticalScrollBarEnabled(false);
moveTracker = new MovementTracker();
}
public boolean onTouchEvent(MotionEvent evt) {
if (moveTracker.track(evt))
if (moveTracker.getDirection() == Direction.HORIZONTAL)
return false;
return super.onTouchEvent(evt);
}
}
PD: MovimientoTracker devuelve True On Track () después de algunos eventos y contará en qué dirección se está moviendo el usuario.
Pero en ese caso, ScrollView sigue recibiendo eventos ya que se devuelve cierto en los primeros eventos.
Cualquier idea sobre cómo puedo manejar los eventos en ViewSwiper cuando es niño devuelve falso (incluso si se devuelven algunos trues).
PD: Puedo dar más información sobre esto si es necesario y aceptar diferentes soluciones también.
Según las respuestas, probé lo siguiente:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
onTouchEvent(ev);
return intercept;
}
public boolean onTouchEvent(MotionEvent evt) {
boolean x = super.onTouchEvent(evt);
if (moveTracker.track(evt)) {
intercept = moveTracker.getDirection() != Direction.VERTICAL;
if (!intercept)
getParent().requestDisallowInterceptTouchEvent(false);
}
return x;
}
Aún nada.
Solución
Prueba esto en onTouchEvent()
del ScrollView
//if (evt.getAction() == MotionEvent.ACTION_MOVE) {
if (moveTracker.track(evt)){
if (moveTracker.getDirection() == Direction.VERTICAL){
//Or the direction you want the scrollview keep moving
getParent().requestDisallowInterceptTouchEvent(true);
}
}
return true;
Actualizar
Pruebe lo siguiente en el ScrollView personalizado
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
super.dispatchTouchEvent(ev);
return false;
}
Y nada más
De esta manera, supongo que MotionEvent funcionará en ambas vistas. Y dado que no entran en conflicto (uno es vertical, el otro es horizontal) esto podría funcionar
Otros consejos
Basado en la respuesta de Weakwire, llegué a la siguiente solución:
En Viewswiper
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(!super.dispatchTouchEvent(ev))
onTouchEvent(ev);
return true;
}
Y en ScrollHorizontal devuelve falso en DispatchTouchEvent cuando ya no necesito.