ScrollView dentro de ViewFlipper

Publica aquí tutoriales, trucos, o pequeñas recetas de cosecha propia sobre desarrollo en Android. SOLO TUTORIALES PROPIOS, los tutoriales de terceros deben ir a la sección de noticias, enlaces y recursos.

ScrollView dentro de ViewFlipper

Notapor david » 25 Ene 2012, 22:31

¡Hola a todos!

Voy a comentar los pasos que he realizado para resolver esto ya que estuve varios días con dolores de cabeza por esto y en internet la información que encontraba era un poco oscura y muy difícil de adaptar a mi código.

Lo que mi aplicación tiene es un ViewFlipper y dentro de él hay 3 RelativeLayout y 1 ScrollView, tal que así:
Código: Seleccionar todo
<ViewFlipper>
    <RelativeLayout 1 ... />
    <RelativeLayout 2 ... />
    <RelativeLayout 3 ... />
    <ScrollView ... />
</ViewFlipper>


Y lo que yo pretendo hacer es que, mediante el deslizado horizontal del dedo sobre la pantalla, me cambie de un RelativeLayout a otro o al ScrollView y viceversa. Para cambiar de un RelativeLayout a otro no existe problema, el problema llega cuando es del ScrollView al RelativeLayout, ya que la pantalla de ScrollView captura el evento de los gestos con el dedo.

Para los movimientos entre RelativeLayouts, declaramos la clase MyGestureDetector, que heredará de SimpleOnGestureListener, necesaria para capturar el evento de movimiento con el dedo mediante el método onFling(...).
Código: Seleccionar todo
public class TuActivity implements OnClickListener {
   // ...
   private static final int SWIPE_MIN_DISTANCE      = 120;
   private static final int SWIPE_MAX_OFF_PATH      = 250;
   private static final int SWIPE_THRESHOLD_VELOCITY   = 200;
   private GestureDetector gestureDetector         = null;
   View.OnTouchListener gestureListener         = null;

   class MyGestureDetector extends SimpleOnGestureListener {
      @Override
      public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
         try {
            if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
               return false;
            desliza(e1, e2, velocityX, velocityY, vf);
         } catch (Exception e) {
            // nothing
         }
         return false;
      }
   }

   // Procedimiento encargado de hacer la animación cuando se captura
   // el movimiento del dedo
   public void desliza(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY, ViewFlipper vfpr){
      if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY)
         moverDerecha(TuActivity.this, vfpr);
      else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY)
         moverIzquierda(TuActivity.this, vfpr);
   }
   
   // Mover a la pantalla siguiente
   public void moverDerecha(Context c, ViewFlipper vfp){
      vfp.setInAnimation(c, tu_animacion);
      vfp.setOutAnimation(c, tu_animacion);
      vfp.showNext();
   }
   
   // Mover a la pantalla anterior
   public void moverIzquierda(Context c, ViewFlipper vfp){
      vfp.setInAnimation(c, tu_animacion);
      vfp.setOutAnimation(c, tu_animacion);
      vfp.showPrevious();
   }

   @Override
   public boolean onTouchEvent(MotionEvent event) {
      if (gestureDetector.onTouchEvent(event))
         return true;
      else
         return false;
   }


Ahora bien, en el método onCreate(...) hacemos lo siguiente:
Código: Seleccionar todo
   @Override
   public void onCreate(Bundle savedInstanceState) {
   // ...
      gestureDetector = new GestureDetector(new MyGestureDetector());
      gestureListener = new View.OnTouchListener() {
         @Override
         public boolean onTouch(View v, MotionEvent event) {
            return gestureDetector.onTouchEvent(event);
         }
      };
           vf = (ViewFlipper) findViewById(R.id.desliza);
           vf.setOnTouchListener(gestureListener);
   // ...
   }


Pues bien, después de muchos quebraderos de cabeza y días de trabajo perdidos, un día se me ocurrió copiar y pegar este mismo código y en el onCreate(...) asignárselo al ScrollView sv en vez de como hice antes con el ViewFlipper vf. Por tanto, lo que hice fue:
- Replicar la variable gestureDetector como gestureSDetector
- Replicar la variable gestureListener como gestureSListener
- Replicar la clase MyGestureDetector como MyScrollGestureDetector. El método onFling(...) permanecerá exactamente igual.
- Replicar lo que escribí antes en el método onCreate(...) pero en este caso con gestureSDetector, gestureSListener y ScrollView sv.


Al final, el método onCreate(...) quedaría así:
Código: Seleccionar todo
   @Override
   public void onCreate(Bundle savedInstanceState) {
   // ...
      gestureDetector = new GestureDetector(new MyGestureDetector());
      gestureListener = new View.OnTouchListener() {
         @Override
         public boolean onTouch(View v, MotionEvent event) {
            return gestureDetector.onTouchEvent(event);
         }
      };
           vf = (ViewFlipper) findViewById(R.id.viewflipper);
           vf.setOnTouchListener(gestureListener);
       
           gestureSDetector = new GestureDetector(new MyScrollGestureDetector());
           gestureSListener = new View.OnTouchListener() {
         @Override
         public boolean onTouch(View v, MotionEvent event) {
            return gestureSDetector.onTouchEvent(event);
         }
      };
       sv = (ScrollView) findViewById(R.id.scrollview);
       sv.setOnTouchListener(gestureSListener);



Solucionado, se acabó el problema de por qué el ScrollView no funcionaba con el movimiento en horizontal del dedo.


Un saludo, espero que les sirva de ayuda y les ahorre gran cantidad de tiempo.
David A. G.
david
 
Mensajes: 50
Registrado: 08 Dic 2011, 21:11
Ubicación: España

Re: ScrollView dentro de ViewFlipper

Notapor sgoliver » 26 Ene 2012, 10:32

Muy interesante David.

Muchas gracias por compartirlo con todos.

Saludos.
------
sgoliver.net blog
www.sgoliver.net
sgoliver
Site Admin
 
Mensajes: 77
Registrado: 28 Oct 2011, 20:24
Ubicación: España

Re: ScrollView dentro de ViewFlipper

Notapor m4rCe » 12 Abr 2012, 23:16

Hola David!..la verdad leí tu post por casualidad, pero estoy tambien trabajando con ViewFlipper..soy muy nueva en esto, y lo que trato de hacer es: en mi main.xml tengo 4 relativelayouts, y quiero pasar a cada uno de ellos con un button ..lo logro hacer con los dos primeros, es decir, estoy en mi primer relative, y pulso el button y paso a mi segundo relative, pero cuando le doy al boton apra pasar al tercero, solamente se queda hay y no pasa nada!! no se que estoy haciendo mal! te dejo el codigo de la actividad del boton para que puedas ver, y si sabes cual es el problema me digas, o si hay una manera diferente de hacerlo, tambien te lo agradeceria

[codigo]

Button next1 = (Button) findViewById (R.id.btn_next1); --> al oprimir "btn_next1" me pasa a mi 2 relativelayout
next.setOnClickListener(new View.OnClickListener() {
public void onClick (View view) {
ViewFlipper vf = (ViewFlipper) findViewById(R.id.details);
vf.setAnimation(AnimationUtils.loadAnimation(view.getContext(), R.anim.push_down_in));
vf.showNext();
}
});


Button next2 = (Button) findViewById (R.id.btn_next2); --> supuse que con el mismo codigo, solo cambiando el nombre del boton, al oprimirlo me pasaria a mi 3 relativelayout, pero simplemente no pasa nada
next.setOnClickListener(new View.OnClickListener() {
public void onClick (View view) {
ViewFlipper vf = (ViewFlipper) findViewById(R.id.details);
vf.setAnimation(AnimationUtils.loadAnimation(view.getContext(), R.anim.push_down_in));
vf.showNext();
}


});
m4rCe
 
Mensajes: 5
Registrado: 12 Abr 2012, 23:08

Re: ScrollView dentro de ViewFlipper

Notapor david » 13 Abr 2012, 10:54

Hola m4rCe,

el error lo tienes en el nombre de las variables que representan los botones. Los botones se llaman next1 y next2 y después usas el evento onClickListener de next.

Un saludo!
David A. G.
david
 
Mensajes: 50
Registrado: 08 Dic 2011, 21:11
Ubicación: España

Re: ScrollView dentro de ViewFlipper

Notapor m4rCe » 13 Abr 2012, 21:17

Oh de por todos los Santos!! jajaajaj si eso era...que error torpe!! Gracias :)
m4rCe
 
Mensajes: 5
Registrado: 12 Abr 2012, 23:08

Re: ScrollView dentro de ViewFlipper

Notapor m4rCe » 17 Abr 2012, 22:17

Daviiiid!! porfis ayudame!! :)

mira estaba intentando hacer lo mio con botoncitos, de modo que si yo le daba al boton de ↓ entonces pasaba al siguiente Relativelayout, y lo mismo si oprimia el botoncito ↑ pasaba al anterior..pero...encontrando este tu post y ver que tu lo haces asi deslizandote, me dieron ganas de intentar hacerlo tambien...y estoy tratando con el codigo que pones aca, pero hay ciertas cositas que no logro entender y quiero que me expliques porfavor. mi Clase principal se llama FlipperActivity que extiende de una Activity, lo que tu pones de codigo, pones "TuActivity implements OnClickListener" no lo enteindo ...y lo cuando declaras el "desliza" y cuando pones "tuactividad.this" ...podrias poner tu codigo completo? o mandarmelo =(
m4rCe
 
Mensajes: 5
Registrado: 12 Abr 2012, 23:08

Re: ScrollView dentro de ViewFlipper

Notapor david » 18 Abr 2012, 12:05

Vamos por partes:
- Tu clase principal deberá ser entonces:
Código: Seleccionar todo
public class FlipperActivity extends Activity implements OnClickListener {
    // ...
}


- Lo de "TuActivity.this" es porque es el parámetro que hay que pasarle a la función. Si te fijas, los métodos "setInAnimation" y "setOutAnimation" necesitan que le pases la actividad como parámetro. Copia y pega el código que he puesto, a excepción del método "desliza", que en tu caso que mueves de arriba a abajo, deberá ser el siguiente:
Código: Seleccionar todo
   public void desliza(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY, ViewFlipper vfpr){
      if(e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY)
         moverArriba(FlipperActivity.this, vfpr);
      else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY)
         moverAbajo(FlipperActivity.this, vfpr);
   }


OJO: Si tu pantalla contiene un RelativeLayout que ya de por sí es deslizable de arriba a abajo (puedes hacer scroll) debido a su tamaño vertical, creo/supongo que el deslizado lo capturará el evento de onTrackballEvent(...). Si te pasa eso ya habrá que buscar otra solución, como, por ejemplo, jugar con las velocidades de deslizado del dedo sobre la pantalla.


Un saludo, espero haberme explicado.
David A. G.
david
 
Mensajes: 50
Registrado: 08 Dic 2011, 21:11
Ubicación: España


Volver a Tutoriales de la Comunidad

cron