Vista ScrollView con niños, cómo interceptar desplazamiento condicional
Tengo un contenedor ViewGroup
, permite llamar a la pantalla dentro de un ScrollView
. Esta vista de contenedor aloja una serie de otras Views
, llamémoslas widgets , y algunas de ellas están interesadas en evitar que ScrollView se desplace y utilice sus propios MotionEvent (por ejemplo, una imagen en forma de paneles)
No puedo averiguar la estrategia de intercepción de eventos apropiados para usar. ScrollView
siempre procesa el evento antes de que los niños o los niños procesen el evento, pero scrollview
está deshabilitado.
- Determinar qué vista se está tocando actualmente mientras el usuario mueve el dedo
- DrawerLayout con HorizontalScrollView en el menú de contenido
- Pasar los toques a la vista bajo
- Custom onInterceptTouchEvent en ListView
- Problemas con Gallery.getChildAt (int position)
He leído sobre emitir getParent().requestDisableInterceptTouchEvent()
en las vistas secundarias si esta vista quiere capturar el evento, pero su onTouchEvent
no se llama, supongo que ScrollView
ha engullido el evento de antemano. Supongo que el hecho de que tengo 2 niveles de capas (contenedor + widgets) impide que esto funcione, supongo que el contenedor ViewGroup
tiene que desempeñar un papel importante aquí, pero no puedo averiguar cuál …
¿Puedo saber, en el nivel onInterceptTouchEvent
ScrollView's
, qué widget en el viewGroup
del contenedor se ha tocado para decidir si debo interceptar o no?
o…
¿Cómo pueden las capas 'widget' en ViewGroup
obtener el evento antes de ScrollView
para que pueda llamar a getParent().onRequestDisableInterceptTouch()
… o es getParent().getParent().onRequestDisableInterceptTouch()
?
Gracias por adelantado
He leído preguntas relacionadas, pero no hay suerte … Manejo de eventos táctiles en ScrollView Android
- Android MediaController intercepta todos los demás eventos táctiles
- Detectar todos los eventos táctiles sin sobrepasar a dispatchTouchEvent ()?
- Compruebe la dirección que se lanzó en un evento de Movimiento android
- ¿Cómo evitar que ScrollView intercepte eventos de clic / toque de la vista detrás de él?
- Ver sólo el registro de MotionEvent.ACTION_DOWN
- Utilice una barra de acción contextual personalizada para la selección de texto de WebView
- Limpiar por defecto algunas toallitas con jQuery touchwipe
- Servicio Android Jelly Bean que recibe todos los eventos de toque
Bueno, después de una noche de coca cola y depuración me las arreglé para conseguir que esto funcione. Comparto la solución sólo en caso de que sea de interés para cualquier persona, porque me tomó bastante tiempo para que funcione.
No conseguí ponerlo en funcionamiento con getParent().onRequestDisableInterceptTouch()
, estaba cerca, pero no pude encontrar una forma para que los widgets secundarios obtengan los MotionEvents que necesitan para desplazarse una vez que intercepté el toque en el padre, Así que aunque el rollo externo se evitó correctamente, los widgets internos no se desplazaron.
Así que la solución es interceptTouchEvents
en los niños SOLAMENTE , y si los niños es desplazable (propiedad conocida), y el toque es ACTION_DOWN, deshabilite la vista de desplazamiento dos niveles arriba. Si el toque es ACTION_UP, activamos la vista de desplazamiento.
Para habilitar / deshabilitar el scrollview sólo intercepto el evento táctil y con un filtro de bandera el evento o no.
Hice tres clases auxiliares, una para el ScrollView, otra para el contenedor, una para los widgets:
Esta clase envuelve todos los widgets y, si llamo a setNeedsScroll (true), los toques serán interceptados, y cuando se toca, le indicará al scrollview que se desactive. Cuando se suelta el tacto, volverá a habilitar la vista de desplazamiento.
class WidgetWrapperLayout extends FrameLayout { private boolean mNeedsScroll=false; public WidgetWrapperLayout(Context context) { super(context); } /** Called anytime, ie, during construction, to indicate that this * widget uses vertical scroll, so we need to disable its container scroll */ public void setNeedsScroll(boolean needsScroll) { mNeedsScroll=needsScroll; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (mNeedsScroll) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: ((SlideLayout)getParent()).setEnableScroll(false); break; case MotionEvent.ACTION_UP: ((SlideLayout)getParent()).setEnableScroll(true); break; } return false; } return super.onInterceptTouchEvent(ev); } }
Este es el contenedor, único hijo de la vista de scrollview
, y tiene los diferentes widgets. Sólo proporciona métodos para los niños para que puedan activar / desactivar el desplazamiento:
public class ContainerLayout extends FrameLayout { public ContainerLayout(Context context) { super(context); } public void setEnableScroll(boolean status) { if (Conf.LOG_ON) Log.d(TAG, "Request enable scroll: "+status); ((StoppableScrollView)getParent()).setScrollEnabled(status); } }
Y finalmente un scrollview capaz de desactivación. Desactiva el scroll 'old-skool', interceptar y bloquear eventos.
public class StoppableScrollView extends ScrollView { private String TAG="StoppableScrollView"; private boolean mDisableScrolling=false; public StoppableScrollView(Context context) { super(context); } /** Enables or disables ScrollView scroll */ public void setScrollEnabled (boolean status) { if (Conf.LOG_ON) Log.d(TAG, "Scroll Enabled "+status); mDisableScrolling=!status; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (mDisableScrolling) return false; return super.onInterceptTouchEvent(ev); } }
Implemente View.OnTouchListener
en su actividad y añada ese oyente a ScrollView. A continuación, devuelve true en onTouchEvent(...)
. Antes de regresar llame al onTouch
de los niños que desea manejar ese evento.
- Android: Modificar las preferencias compartidas de otra aplicación
- Honeycomb Hardware Acceleration no parece funcionar con setColorFilter