Android: Cómo detectar cuando un rollo ha terminado
-
21-09-2019 - |
Pregunta
Estoy utilizando el método de OnScroll GestureDetector.SimpleOnGestureListener para desplazarse un gran mapa de bits en un lienzo. Cuando el rollo ha terminado quiero volver a dibujar el mapa de bits en el caso de que el usuario desea desplazarse más lejos ... fuera del borde del mapa de bits, pero no puedo ver cómo detectar cuando el desplazamiento ha terminado (el usuario ha levantado su dedo de la pantalla).
e2.getAction () siempre parece devolver el valor 2, de modo que no es de ayuda. e2.getPressure parece volver valores bastante constantes (alrededor de 0,25) hasta que la llamada OnScroll final cuando la presión parece caer a aproximadamente 0,13. Supongo que podría detectar esta reducción de la presión, pero esta será lejos de toda prueba.
Tiene que haber una mejor manera:? Puede ayudar a nadie, por favor
Solución
Así es como he resuelto 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);
}
Otros consejos
Usted debe echar un vistazo a http://developer.android.com /reference/android/widget/Scroller.html. Sobre todo esto podría ser de ayuda (ordenadas por fecha):
isFinished();
computeScrollOffset();
getFinalY(); getFinalX(); and getCurrY() getCurrX()
getDuration()
Esto implica que usted tiene que crear una rueda de desplazamiento.
Si desea utilizar tocando también se podría utilizar GestureDetector y definir su propio desplazamiento de la lona. El siguiente ejemplo es la creación de un ScrollableImageView y con el fin de usarlo hay que definir las medidas de su imagen. Usted puede definir su propio intervalo de desplazamiento y después de terminar su movimiento en sentido vertical de la imagen se redibuja una.
http://www.anddev.org/viewtopic.php?p = 31487 # 31487
En función de su código debe tener en cuenta invalidar (int l, int t, r int, int b); para la invalidación.
SimpleOnGestureListener.onFling()
Parece que tendrá lugar cuando termina un desplazamiento (es decir, el usuario deja la marcha del dedo), eso es lo que estoy utilizando y funciona muy bien para mí.
Volviendo a esto después de unos meses he seguido un camino diferente: el uso de un Handler (como en la muestra de la serpiente Android) para enviar un mensaje a la aplicación cada 125 milisegundos que le pide que para comprobar si un desplazamiento tiene ha comenzado y si más de 100 milisegundos que han transcurrido desde el último evento de desplazamiento.
Esto parece funcionar bastante bien, pero si alguien puede ver alguna desventaja o posibles mejoras le agradecería a escuchar de ellos.
El correspondiente el código 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;
// desplazamiento ha terminado, por lo que insertar código aquí
// que llama doDrawing () método
// para volver a trazar mapas de bits re-centrada, donde terminó de desplazamiento
[ 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 mapa de bits grande búfer en el lienzo de la vista // posicionado para tener en cuenta cualquier desplazamiento que está en curso
}
public void doDrawing() {
// código para hacer dibujo detallado (y tiempo) // en mapa de bits grande tampón
// la siguiente instrucción restablece el reloj Tiempo de comprobación // el reloj se inicia cuando la primera // 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 la vista que se llama // que traza el mapa de bits búfer en la pantalla // desplazado a tener en cuenta el desplazamiento
[MyView].invalidate();
}
// resto de la clase MyGestureDetector
}
Yo estaba buscando en este mismo tema. Vi respuesta Akos Cz a su pregunta. He creado algo similar, pero con mi versión me di cuenta de que sólo trabajó durante un desplazamiento normal - es decir, uno que no genere una aventura. Pero si una aventura hizo llegar generada - sin importar si Procesé una aventura o no, entonces no detectamos el "ACTION_UP" en "onTouchEvent". Ahora quizás esto era simplemente algo con mi aplicación, pero si fuera yo no podía entender por qué.
Después de investigaciones adicionales, me di cuenta de que durante una aventura, el "ACTION_UP" se pasó a "onFling" en "e2" cada vez. Así que pensé que debe ser por eso que no estaba siendo manejado en "onTouchEvent" en esos casos.
Para hacer que funcione para mí que sólo tenía que llamar a un método para manejar la "ACTION_UP" en "onFling" y luego funcionó para ambos tipos de desplazamiento. A continuación se presentan los pasos exactos que tomé para poner en práctica en mi aplicación:
-initialized un "gestureScrolling" booleano para "falso" en un constructor.
-I ponerlo en "true" en "OnScroll"
-Creado un método para controlar el evento "ACTION_UP". Dentro de ese evento, se restablece "gestureSCrolling" false y luego hice el resto del procesamiento que tenía que hacer.
-en "onTouchEvent", si se ha detectado un "ACTION_UP" y "gestureScrolling" = true, entonces 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 de manejar "ACTION_UP" dentro de "onFling"
Estoy seguro de que sea demasiado tarde para usted, sin embargo, parece que he encontrado la solución correcta a su pregunta original y no es necesaria la intención.
Si está utilizando desplazador / OverScroller objeto de desplazamiento debe comprobar el valor de retorno de la siguiente función.
public boolean computeScrollOffset()
disfrutar
Harvinder
Esto es lo que funcionó para mí.
He enriquecido el con () método existente GestureDetector.OnGestureListener onFingerUp. Este oyente hace todo como la incorporada en GestureDetector y también puede detectar el evento dedo hacia arriba (no es onFling () ya que esto se llama sólo cuando el dedo se levanta junto con una acción de golpe rápido).
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;
}
}
No he hecho esto por mí mismo, pero mirando onTouch () siempre se obtiene una secuencia de 0 <2> 1, por lo que al final tiene que ser un 1 para la elevación del dedo.
No sé Android, pero mirando a la documentación parece Rob es correcta: Android ACTION_UP constante Prueba a revisar para ACTION_UP de getAction ()?
Edit: ¿Qué e1.getAction () muestran? ¿Alguna vez volver ACTION_UP? La documentación dice que tiene el evento hasta inicial, así que tal vez también va a notificar cuando el puntero está arriba
Edit: Sólo dos más cosas que se me ocurren. ¿Desea devolver falsa en algún momento? Eso puede evitar que ACTION_UP
La única otra cosa que me gustaría probar es tener un evento independiente, tal vez onDown, y establecer un indicador dentro OnScroll como isScrolling. Cuando se da a ACTION_UP onDown y isScrolling se establece a continuación, usted podría hacer lo que quiera y restablecer isScrolling a falso. Es decir, suponiendo onDown obtiene la llamada junto con OnScroll y getAction volverá ACTION_UP durante onDown
No he probado / usado esto, pero una idea para un enfoque:
Parada / interrumpen lo vuelve a dibujar la lona en cada evento de desplazamiento esperan 1s y luego empiezan a volver a dibujar la lona en CADA desplazamiento.
esto conducirá a la realización de la redibujar sólo al final de desplazamiento, ya que sólo el último desplazamiento en realidad será ininterrumpida para el redibujado para completar.
esperanza esta idea le ayuda a:)
Extracto del evento OnScroll de API GestureListener: enlace de texto
abstract boolean pública OnScroll (MotionEvent e1, e2 MotionEvent, float distanceX, flotar distanceY) Desde: API Nivel 1
Devoluciones * True si el evento se consume, y false
Tal vez una vez que el evento ha sido consumido, la acción está terminado y el usuario ha tomado su dedo de la pantalla o al menos terminado de 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 sea necesario
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;
}
}
Mi intento de añadir funcionalidad adicional para detector gesto. Espero que ayuda a alguien puso su tiempo para un mejor uso ...
https://gist.github.com/WildOrangutan/043807ddbd68978179b7cea3b53c71e8