Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Android: Cómo detectar cuándo ha finalizado un desplazamiento

Estoy utilizando el método onScroll de GestureDetector.SimpleOnGestureListener para desplazar un mapa de bits grande en un lienzo. Cuando el desplazamiento ha terminado quiero volver a dibujar el mapa de bits en caso de que el usuario quiere desplazarse más lejos … fuera del borde del mapa de bits, pero no puedo ver cómo detectar cuando el rollo ha terminado (el usuario ha levantado el dedo Desde la pantalla).

E2.getAction () siempre parece devolver el valor 2 para que no sea de ayuda. E2.getPressure parece devolver valores bastante constantes (alrededor de 0.25) hasta la llamada final onScroll cuando la presión parece caer a aproximadamente 0.13. Supongo que podría detectar esta reducción en la presión, pero esto estará lejos de ser infalible.

Debe haber una mejor manera: ¿alguien puede ayudar, por favor?

  • Desplazamiento suave de una lona en Android
  • Cómo hacer que RecyclerView se desplace sin problemas?
  • Cómo evitar que RecyclerView consuma eventos táctiles
  • Android: HorizontalScrollView smoothScroll tiempo de animación
  • 12 Solutions collect form web for “Android: Cómo detectar cuándo ha finalizado un desplazamiento”

    He aquí cómo resolví el problema. Espero que esto ayude.

     // declare class member variables private GestureDetector mGestureDetector; private OnTouchListener mGestureListener; private boolean mIsScrolling = false; public void initGestureDetection() { // Gesture detection mGestureDetector = new GestureDetector(new SimpleOnGestureListener() { @Override public boolean onDoubleTap(MotionEvent e) { handleDoubleTap(e); return true; } @Override public boolean onSingleTapConfirmed(MotionEvent e) { handleSingleTap(e); return true; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // i'm only scrolling along the X axis mIsScrolling = true; handleScroll(Math.round((e2.getX() - e1.getX()))); return true; } @Override /** * Don't know why but we need to intercept this guy and return true so that the other gestures are handled. * https://code.google.com/p/android/issues/detail?id=8233 */ public boolean onDown(MotionEvent e) { Log.d("GestureDetector --> onDown"); return true; } }); mGestureListener = new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if (mGestureDetector.onTouchEvent(event)) { return true; } if(event.getAction() == MotionEvent.ACTION_UP) { if(mIsScrolling ) { Log.d("OnTouchListener --> onTouch ACTION_UP"); mIsScrolling = false; handleScrollFinished(); }; } return false; } }; // attach the OnTouchListener to the image view mImageView.setOnTouchListener(mGestureListener); } 

    Usted debe echar un vistazo a http://developer.android.com/reference/android/widget/Scroller.html . Especialmente esto podría ser de ayuda (ordenado por relevancia):

     isFinished(); computeScrollOffset(); getFinalY(); getFinalX(); and getCurrY() getCurrX() getDuration() 

    Esto implica que usted tiene que crear un Scroller.

    Si desea utilizar el toque, también puede usar GestureDetector y definir su propio desplazamiento de la lona. El ejemplo siguiente está creando un ScrollableImageView y para poder usarlo es necesario definir las medidas de su imagen. Usted puede definir su propio rango de desplazamiento y después de terminar su desplazamiento de la imagen se vuelve a dibujar.

    http://www.anddev.org/viewtopic.php?p=31487#31487

    Dependiendo de su código, debería considerar invalidate (int l, int t, int r, int b); Para la invalidación.

    Volviendo a esto después de unos meses, ahora he seguido una pista diferente: usando un Handler (como en la muestra de Android Snake) para enviar un mensaje a la aplicación cada 125 milisegundos que le pide comprobar si se ha iniciado un rollo y Si ha transcurrido más de 100 milisegundos desde el último evento de desplazamiento.

    Esto parece funcionar bastante bien, pero si alguien puede ver los inconvenientes o posibles mejoras que debería estar agradecido de oír de ellos.

    El código relevante está en la clase MyView:

     public class MyView extends android.view.View { ... private long timeCheckInterval = 125; // milliseconds private long scrollEndInterval = 100; public long latestScrollEventTime; public boolean scrollInProgress = false; public MyView(Context context) { super(context); } private timeCheckHandler mTimeCheckHandler = new timeCheckHandler(); class timeCheckHandler extends Handler{ @Override public void handleMessage(Message msg) { long now = System.currentTimeMillis(); if (scrollInProgress && (now>latestScrollEventTime+scrollEndInterval)) { scrollInProgress = false; 

    // El rollo ha terminado, así que inserte el código aquí

    // que llama al método doDrawing ()

    // para volver a dibujar el mapa de bits centrado de nuevo

      [ layout or view ].invalidate(); } this.sleep(timeCheckInterval); } public void sleep(long delayMillis) { this.removeMessages(0); sendMessageDelayed(obtainMessage(0), delayMillis); } } } @Override protected void onDraw(Canvas canvas){ super.onDraw(canvas); 

    // código para dibujar un mapa de bits de búfer grande en el lienzo de la vista // posicionado para tener en cuenta cualquier rollo que esté en progreso

     } public void doDrawing() { 

    // código para hacer un dibujo detallado (y demorado) // en un mapa de bits de buffer grande

    // la siguiente instrucción restablece el reloj Time Check // el reloj se inicia por primera vez cuando // la actividad principal llama a este método cuando se inicia la aplicación

      mTimeCheckHandler.sleep(timeCheckInterval); } 

    // resto de la clase MyView

    }

    Y en la clase MyGestureDetector

     public class MyGestureDetector extends SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { [MyView].scrollInProgress = true; long now = System.currentTimeMillis(); [MyView].latestScrollEventTime =now; [MyView].scrollX += (int) distanceX; [MyView].scrollY += (int) distanceY; 

    // la siguiente instrucción hace que el método onDraw de View sea llamado // que traza el mapa de bits del buffer en la pantalla // desplazado para tener en cuenta el rollo

      [MyView].invalidate(); } 

    // resto de la clase MyGestureDetector

    }

     SimpleOnGestureListener.onFling() 

    Parece tener lugar cuando un rollo termina (es decir, el usuario deja ir el dedo), eso es lo que estoy usando y funciona muy bien para mí.

    Yo estaba buscando en este mismo tema. Vi la respuesta de Akos Cz a su pregunta. He creado algo similar, pero con mi versión me di cuenta de que sólo funcionaba para un desplazamiento regular – es decir, que no genera un fling. Pero si un fling se generó – sin importar si he procesado un fling o no, entonces no detectó el "ACTION_UP" en "onTouchEvent". Ahora tal vez esto era sólo algo con mi implementación, pero si era yo no podía entender por qué.

    Después de una investigación más profunda, me di cuenta de que durante un fling, el "ACTION_UP" se pasó a "onFling" en "e2" cada vez. Así que pensé que debe ser por qué no se trataba en "onTouchEvent" en esos casos.

    Para hacer que funcione para mí sólo tuve que llamar a un método para manejar el "ACTION_UP" en "onFling" y luego funcionó para ambos tipos de desplazamiento. A continuación se muestran los pasos exactos que tomé para implementar en mi aplicación:

    -initialized un "gestureScrolling" booleano a "false" en un constructor.

    -Lo establezco en "true" en "onScroll"

    -created un método para manejar el evento "ACTION_UP". Dentro de ese evento, restablecer "gestureSCrolling" a falso y luego hizo el resto del proceso que necesitaba hacer.

    -in "onTouchEvent", si se detectó un "ACTION_UP" y "gestureScrolling" = true, llamé a mi método para manejar "ACTION_UP"

    -Y la parte que hice que era diferente era: También llamé a mi método para manejar "ACTION_UP" dentro de "onFling".

    Estoy seguro de que es demasiado tarde para usted, sin embargo, parece que he encontrado la solución correcta a su pregunta original y no es necesario la intención.

    Si está utilizando Scroller / OverScroller Object para desplazarse, debe comprobar el valor devuelto de la siguiente función.

     public boolean computeScrollOffset() 

    disfrutar

    Harvinder

    Yo no he hecho esto yo mismo, pero al mirar onTouch () siempre se obtiene una secuencia 0 <2> 1, por lo que el final tiene que ser un 1 para levantar el dedo.

    No conozco Android, pero mirando la documentación parece que Rob tiene razón: Android ACTION_UP constante Prueba a buscar ACTION_UP de getAction ()?

    Editar: ¿Qué muestra e1.getAction ()? ¿Alguna vez regresa ACTION_UP? La documentación dice que contiene el evento inicial, por lo que tal vez también se notificará cuando el puntero está hacia arriba

    Editar: Sólo dos cosas más en las que puedo pensar. ¿Estás volviendo falso en cualquier momento? Esto puede impedir que ACTION_UP

    La única otra cosa que intentaría es tener un evento separado, tal vez onDown, y establecer una bandera dentro de onScroll como isScrolling. Cuando ACTION_UP se da a onDown y isScrolling se establece entonces usted podría hacer lo que quiera y restablecer isScrolling a false. Es decir, asumiendo onDown se llama junto con onScroll, y getAction devolverá ACTION_UP durante onDown

    No he intentado / utilizado esto, pero una idea para un enfoque:

    Detener / interrumpir el dibujo de dibujo en CADA evento de desplazamiento esperar 1 s y luego comenzar a dibujar nueva página en CADA rollo.

    Esto llevará a realizar el redibujo sólo en el final de desplazamiento, ya que sólo el último desplazamiento en realidad será ininterrumpido para el redibujo para completar.

    Espero que esta idea te ayude

    Extracto del evento onScroll de GestureListener API: link text

    Público resumen booleano onScroll (MotionEvent e1, MotionEvent e2, flotante distanceX, float distanceY) Desde: API Nivel 1

    Devuelve * true si el evento se consume, sino false

    Tal vez una vez que el evento se ha consumido, la acción ha terminado y el usuario ha sacado el dedo de la pantalla o por lo menos ha terminado esta acción onScroll

    A continuación, puede utilizar esto en una instrucción IF para buscar == true y luego comenzar con la siguiente acción.

    Creo que esto funcionará como necesites

     protected class SnappingGestureDetectorListener extends SimpleOnGestureListener{ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY){ boolean result = super.onScroll(e1, e2, distanceX, distanceY); if(!result){ //Do what you need to do when the scrolling stop here } return result; } } 

    Esto es lo que funcionó para mí.

    He enriquecido el GestureDetector.OnGestureListener existente con el método onFingerUp () . Este oyente hace todo como el GestureDetector incorporado y también puede escuchar el dedo hasta el evento (no es onFling (), ya que esto se llama sólo cuando el dedo se levanta, junto con una acción rápida).

     import android.content.Context; import android.os.Handler; import android.view.GestureDetector; import android.view.MotionEvent; public class FingerUpGestureDetector extends GestureDetector { FingerUpGestureDetector.OnGestureListener fListener; public FingerUpGestureDetector(Context context, OnGestureListener listener) { super(context, listener); fListener = listener; } public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, OnGestureListener fListener) { super(context, listener); this.fListener = fListener; } public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, Handler handler, OnGestureListener fListener) { super(context, listener, handler); this.fListener = fListener; } public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, Handler handler, boolean unused, OnGestureListener fListener) { super(context, listener, handler, unused); this.fListener = fListener; } public interface OnGestureListener extends GestureDetector.OnGestureListener { boolean onFingerUp(MotionEvent e); } public static class SimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener implements FingerUpGestureDetector.OnGestureListener { @Override public boolean onFingerUp(MotionEvent e) { return false; } } @Override public boolean onTouchEvent(MotionEvent ev) { if (super.onTouchEvent(ev)) return true; if (ev.getAction() == MotionEvent.ACTION_UP) { return fListener.onFingerUp(ev); } return false; } } 
    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.