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

¿Fue útil?

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top