android: ViewPager y HorizontalScrollVIew

Tengo un HorizontalScrollView dentro de mi ViewPager . Configuro requestDisallowInterceptTouchEvent(true); para HorizontalScrollView pero el ViewPager todavía está interceptando eventos táctiles. ¿Hay algún otro comando que pueda usar para evitar que el padre y antepasados ​​de una Vista intercepten los eventos táctiles?

nota: el HorizontalScrollView solo ocupa la mitad de la pantalla.

Yo tuve el mismo problema. Mi solución fue:

  1. Cree una subclase de ViewPager y agregue una propiedad llamada childId .
  2. Cree un setter para la propiedad childId y establezca el ID de HorizontalScrollView .
  3. onInterceptTouchEvent() en la subclase de ViewPager y si la propiedad childId es mayor que 0, obtenga ese elemento secundario y, si el evento está en el área HorizontalScrollView , devuelva false.

Código

 public class CustomViewPager extends ViewPager { private int childId; public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (childId > 0) { View scroll = findViewById(childId); if (scroll != null) { Rect rect = new Rect(); scroll.getHitRect(rect); if (rect.contains((int) event.getX(), (int) event.getY())) { return false; } } } return super.onInterceptTouchEvent(event); } public void setChildId(int id) { this.childId = id; } } 

En el método onCreate()

 viewPager.setChildId(R.id.horizontalScrollViewId); adapter = new ViewPagerAdapter(this); viewPager.setAdapter(adapter); 

Espero que esto ayude

Gracias por la respuesta. Modifiqué un poco su solución y logré hacer que los ViewPagers nesteds funcionen:

 public class CustomViewPager extends ViewPager { private int childId; public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (childId > 0) { ViewPager pager = (ViewPager)findViewById(childId); if (pager != null) { pager.requestDisallowInterceptTouchEvent(true); } } return super.onInterceptTouchEvent(event); } public void setChildId(int id) { this.childId = id; } } 

Por lo tanto, sé que esta pregunta es bastante antigua, pero he venido con una solución que creo que tiene algunas ventajas adicionales a la publicada aquí. Una situación que podría ocurrir es que podría tener más de un HorizontalScrollView dentro de mi ViewPager (lo que hago), y luego tendría que proporcionar toneladas de Ids a ViewPager para que siempre pueda verificar si hay conflictos táctiles infantiles.

Analicé la fuente de ViewPager y descubrí que usan este método llamado “canScroll” para determinar si se puede desplazar una vista secundaria. Afortunadamente, no fue estático ni definitivo, así que podría anularlo. Dentro de ese método que se llamó el “booleano ViewCompat.canScrollHorizontally (View, int)” (el que siempre devuelve false para SDK <14). Mi solución fue:

 public class CustomViewPager extends ViewPager { public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); } public CustomViewPager(Context context) { super(context); } protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { return super.canScroll(v, checkV, dx, x, y) || (checkV && customCanScroll(v)); } protected boolean customCanScroll(View v) { if (v instanceof HorizontalScrollView) { View hsvChild = ((HorizontalScrollView) v).getChildAt(0); if (hsvChild.getWidth() > v.getWidth()) return true; } return false; } } 

Por lo tanto, si tiene una clase diferente de Vista dentro de su ViewPager que también debería recibir arrastres horizontales, simplemente cambie CustomCanScroll (Ver) para que pueda regresar si el toque no debe ser interceptado o no.

El booleano checkV es verdadero si la vista actual también debe verificarse para ‘scrollability’, es por eso que también deberíamos verificar eso.

Espero que esto ayude en futuros problemas como este (o si hay una solución mejor, o una oficial de la plataforma de Android, házmelo saber).

No sé si ya has resuelto el problema o no. Pero ninguna de las respuestas anteriores funciona correctamente. Entonces creo que es necesario para aquellas personas que podrían estar buscando soluciones con sufrimiento.

De hecho, la solución es bastante simple si lee el documento oficial sobre el manejo de eventos táctiles en ViewGroup.

Primero necesitas entender el uso de

ViewParent.requestDisallowInterceptTouchEvent (boolean) , llámalo a una vista principal para indicar que no debe interceptar eventos táctiles con onInterceptTouchEvent (MotionEvent) .

Luego debe interceptar los eventos y asegurarse de que el ViewGroup padre de su HorizontalScrollView no despache más los eventos.

Por lo tanto, configure OnToushListener para usted HorizontalScrollView. Detectando el aterrizaje y movimiento de eventos, luego establece requestDisallowInterceptTouchEvent (verdadero) en su padre (ViewPager o algo más) para asegurarte de que los eventos sean manejados por HorizontalScrollView.

Por supuesto, puede poner estos códigos debajo en sus componentes CustomHorizontalScrollView para que puedan ser reutilizados.

Esperando que ayude. 😉

 horizontalScrollView.setOnTouchListener(new View.OnTouchListener() { float rawX; int mTouchSlop = ViewConfiguration.get(getActivity()).getScaledTouchSlop(); @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: v.getParent().requestDisallowInterceptTouchEvent(true); rawX = event.getRawX(); break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: v.getParent().requestDisallowInterceptTouchEvent(false); rawX = 0f; break; case MotionEvent.ACTION_MOVE: if (Math.abs(rawX - event.getRawX()) > mTouchSlop) v.getParent().requestDisallowInterceptTouchEvent(true); break; } return false; } 

Aquí hay otra solución que funcionó para mí,

Crear un ViewPager personalizado

 public class NoScrollViewPager extends ViewPager { private boolean scrollDisable = false; public NoScrollViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if(scrollDisable) { return false; } else { return super.onInterceptTouchEvent(ev); } } public void disableScroll() { scrollDisable = true; } public void enableScroll() { scrollDisable = false; } } 

Y luego agregue OnTouchListener a su elemento, ya sea un HorizontalScrollView o Galería o cualquier otra cosa que no desee que el viewpager se desplace cuando se toca.

 gf.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View arg0, MotionEvent ev) { switch(ev.getAction()) { case MotionEvent.ACTION_DOWN: viewPager.disableScroll(); break; case MotionEvent.ACTION_UP: viewPager.enableScroll(); break; } return false; } }); 

La solución de Fede no funcionó muy bien para mí. Mi HorizontalScrollVIew tenía áreas en las que no captaba ninguna entrada (clic, deslizar …). Supongo que getHitRect () tiene que hacer algo con eso. Después de reemplazarlo con el siguiente código todo funcionó bien.

Es posible agregar varias vistas HorizontalScrollVIew o cualquier otra vista que también requiera enfoque.

 public class CustomViewPager extends ViewPager { private ArrayList children; public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); children = new ArrayList(); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (children.size() > 0) { for(int i=0; i 

En XML, tendrá algo como esto:

 

En el método onCreate ():

 mPager = (CustomViewPager) findViewById(R.id.pager); mPager.setAdapter(mAdapter); mPager.addChildId(R.id.avatarImageView); 

En el método OnTouchListener () para la vista que ha agregado a los elementos secundarios de CustomViewPager:

 case MotionEvent.ACTION_DOWN: v.setPressed(true); . . . case MotionEvent.ACTION_UP: v.setPressed(false); 

Estaba teniendo problemas con una pequeña vista de galería al pie de mi primera página en un grupo de viewpager. Al deslizar la vista de la galería, el foco se movería entre mover los elementos de la galería o el visor.

La anulación de ViewPager como se indica arriba y la configuración de requestDisallowInterceptTouchEvent resolvió mi problema. Las páginas ya no cambian al deslizar la vista de la galería. Creo que es una solución importante para quienes usan galleryviews con viewpager.

Esto también funcionará para viewpager dentro de una vista de desplazamiento: https://stackoverflow.com/a/2655740/969325

Descubrí que si tienes un ViewPager en un ScrollView y quieres que siempre permanezca enfocado, cuando lo tocas y el ScrollView nunca obtiene un foco, esto hace eso.

  mViewPager= (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(adapter); mViewPager.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { mViewPager.getParent().requestDisallowInterceptTouchEvent(true); return false; } }); 

después de probar mucha solución, encuentro esto. en MyPagerView:

 @Override public boolean onTouchEvent(MotionEvent event) { if (childId > 0) { View scroll = findViewById(childId); if (scroll != null && mGestureDetector.onTouchEvent(event)) { return false; } } return super.onTouchEvent(event); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (childId > 0) { HorizontalScrollView scroll = (HorizontalScrollView)findViewById(childId); if (scroll != null && mGestureDetector.onTouchEvent(event)) { return false; } } return super.onInterceptTouchEvent(event); } 

Entonces, modifiqué la respuesta de Fede porque estaba deshabilitando el toque en la misma área en las páginas alrededor de la que yo quería. Además, pude agregar varias vistas porque estoy lidiando con muchos gráficos y vistas interactivas que usan interactividad horizontal de arrastrar / soltar. De esta forma puedes agregar

 public class CustomViewPager extends ViewPager { private List lateralTouchViews = new ArrayList<>(); public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { for(int i = 0; i< lateralTouchViews.size(); i++){ View scroll = findViewById(lateralTouchViews.get(i).id); if (scroll != null && getCurrentItem() == lateralTouchViews.get(i).itemPosition) { Rect rect = new Rect(); scroll.getHitRect(rect); if (rect.contains((int) event.getX(), (int) event.getY())) { return false; } } } return super.onInterceptTouchEvent(event); } public void addConflict(int id, int pageIndex) { lateralTouchViews.add(new ViewFocus(id, pageIndex)); } public class ViewFocus{ int id; int itemPosition; public ViewFocus(int id, int itemPosition){ this.id = id; this.itemPosition = itemPosition; } } 

}