Domanda

Sto usando il metodo onscroll di GestureDetector.SimpleOnGestureListener per scorrere una grande bitmap su una tela. Quando il rotolo è terminato voglio ridisegnare la bitmap nel caso in cui l'utente vuole scorrere ulteriormente ... fuori dal bordo della bitmap, ma non riesco a vedere come rilevare quando il rotolo è terminato (l'utente ha alzato il dito dalla schermata).

e2.getAction () sembra sempre di restituire il valore 2 in modo che non è di aiuto. e2.getPressure sembra tornare valori abbastanza costanti (circa 0,25) finché la chiamata onscroll finale quando la pressione sembra cadere a circa 0,13. Suppongo che ho potuto rilevare questa riduzione della pressione, ma questo sarà tutt'altro che infallibile.

Ci deve essere un modo migliore:? Chiunque può aiutare, si prega

È stato utile?

Soluzione

Ecco come ho risolto il problema. Spero che questo aiuti.

// 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);
}

Altri suggerimenti

Si dovrebbe dare un'occhiata a http://developer.android.com /reference/android/widget/Scroller.html . Soprattutto questo potrebbe essere di aiuto (ordinati per rilevanza):

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

Questo implica che si deve creare uno scroller.

Se si desidera utilizzare toccando si potrebbe anche usare GestureDetector e definire il proprio scorrimento tela. Il seguente esempio è la creazione di uno ScrollableImageView e per utilizzarlo è necessario definire le misure della vostra immagine. È possibile definire un intervallo di scorrimento e dopo aver terminato il vostro scorrimento l'immagine viene ridisegnata.

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

A seconda del codice che dovrebbe prendere in considerazione invalidare (int l, int t, int r, int b); per l'annullamento.

SimpleOnGestureListener.onFling() 

Sembra avvenire quando un rotolo finisce (vale a dire l'utente lascia il go dito), questo è quello che sto usando e funziona benissimo per me.

Tornando a questo dopo un paio di mesi ora ho seguito una strada diversa: con un Handler (come nel campione di Snake Android) per inviare un messaggio al app ogni 125 millisecondi, che spinge per controllare se uno Scroll ha stato avviato e se più di 100 millisecondi da quando l'ultimo evento di scorrimento.

Questo sembra funzionare abbastanza bene, ma se chiunque può vedere eventuali inconvenienti o possibili miglioramenti sarei grato di sentire di loro.

La rilevante il codice è nella classe 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;

// scorrimento è terminato, quindi inserire il codice qui

// che chiama doDrawing () Metodo

// per ridisegnare bitmap ri-centrate dove finiva di scorrimento

                    [ 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);

// codice per disegnare bitmap di grandi dimensioni del buffer su tela della vista // posizionato per tener conto di qualsiasi rotolo che è in corso

}

public void doDrawing() {

// codice per fare dettagliato (e che richiede tempo) Disegno // su bitmap grande tampone

// la seguente istruzione resetta il check orologio // l'orologio è iniziato quando // l'attività principale chiama questo metodo quando l'applicazione si avvia

        mTimeCheckHandler.sleep(timeCheckInterval);
}

// resto della classe MyView

}

e nella classe 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;

// l'istruzione successiva causa della vista del metodo OnDraw da chiamare // che riporta la bitmap tampone sullo schermo // spostato a tener conto del rotolo

    [MyView].invalidate();

}

// resto della classe MyGestureDetector

}

che stavo cercando in questo stesso problema. Ho visto Akos Cz risposta alla tua domanda. Ho creato qualcosa di simile, ma con la mia versione ho notato che ha funzionato solo per un rotolo regolare - il che significa uno che non genera un flirt. Ma se una scappatella ha ottenuto generato - a prescindere se ho elaborato una scappatella o no, allora non ha rilevato la "ACTION_UP" in "onTouchEvent". Ora, forse questo era solo qualcosa con la mia realizzazione, ma se fosse non riuscivo a capire perché.

Dopo ulteriori indagini, ho notato che nel corso di una scappatella, il "ACTION_UP" è stata approvata in "onFling" in "e2" ogni volta. Così ho pensato che deve essere il motivo per cui non veniva gestita in "onTouchEvent" in quei casi.

Per farlo funzionare per me ho avuto solo per chiamare un metodo per gestire la "ACTION_UP" in "onFling" e poi ha funzionato per entrambi i tipi di scorrimento. Qui di seguito sono i passaggi esatti ho preso per attuare nella mia app:

-initialized un valore booleano "gestureScrolling" a "false" in un costruttore.

-I impostare su "true" in "onscroll"

-Creato un metodo per gestire l'evento "ACTION_UP". All'interno di quella manifestazione, a reimpostare "gestureSCrolling" false e poi ha fatto il resto del trattamento che dovevo fare.

-in "onTouchEvent", se è stato rilevato un "ACTION_UP" e "gestureScrolling" = vero, allora ho chiamato il mio metodo per gestire "ACTION_UP"

-E la parte che ho fatto era diverso era:. Ho anche chiamato il mio metodo per gestire "ACTION_UP" all'interno di "onFling"

Sono sicuro che sia troppo tardi per voi, però, sembra che ho trovato la soluzione giusta alla tua domanda originale e non è necessario l'intenzione.

Se si utilizza Scroller / OverScroller oggetto per lo scorrimento si dovrebbe verificare il valore restituito dalla seguente funzione.

public boolean computeScrollOffset() 

godere

Harvinder

Questo è ciò che ha funzionato per me.

Ho arricchito il GestureDetector.OnGestureListener con onFingerUp () metodo esistente. Questo ascoltatore fa tutto come il built-in GestureDetector e può anche ascoltare il dito verso l'alto evento (non è onFling () in quanto questo viene chiamato solo quando il dito viene sollevato insieme ad un'azione di colpo rapido).

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;
    }
}

Non ho fatto io stesso, ma guardando onTouch () si ottiene sempre una sequenza di 0 <2> 1, quindi alla fine deve essere un 1 per ascensore dito.

Non so Android, ma guardando la documentazione sembra Rob è giusto: Android ACTION_UP costante Prova a controllare per ACTION_UP da getAction ()?

Modifica: Cosa e1.getAction () mostrano? Ha mai tornare ACTION_UP? La documentazione dice che tiene l'evento verso il basso iniziale, quindi forse sarà anche avvisare quando il puntatore è su

Edit: Solo due più cose mi vengono in mente. Stai tornando falso in qualsiasi momento? Che possono impedire ACTION_UP

L'unica altra cosa che mi piacerebbe provare è quello di avere un evento separato, forse onDown, e impostare un flag all'interno onscroll come isScrolling. Quando ACTION_UP è dato a onDown e isScrolling è impostato allora si potrebbe fare quello che vuoi e reimpostare isScrolling false. Cioè, supponendo onDown viene chiamato insieme a onscroll e getAction tornerà ACTION_UP durante onDown

Non ho provato / usato questo, ma un'idea per un approccio:

arresto / interrompono lo ridisegna tela su ogni evento scroll aspettare 1s e quindi avviare ridisegnare tela su OGNI scorrimento.

questo porterà ad eseguire il ridisegno solo a fine scorrimento come solo l'ultimo di scorrimento sarà effettivamente senza interruzioni per il redraw per completare.

speranza questa idea vi aiuta:)

Estratto dalla manifestazione onscroll da GestureListener API: link testuale

  

public boolean astratto onscroll   (MotionEvent e1, e2 MotionEvent, galleggiante   distanceX, float distanceY) Dal: API   Livello 1

     

Returns       * True se l'evento è consumato, altrimenti false

Forse una volta che l'evento è stato consumato, l'azione è terminata e l'utente ha preso il loro dito dallo schermo o almeno terminato questa azione onscroll

È quindi possibile utilizzare questo in un'istruzione IF per la ricerca di == true e poi iniziare con la prossima azione.

Credo che questo funzionerà come è necessario

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;
    }

}

Il mio tentativo di aggiungere ulteriori funzionalità al rilevatore gesto. Speranza che aiuta qualcuno ha messo il suo tempo per utilizzare al meglio ...

https://gist.github.com/WildOrangutan/043807ddbd68978179b7cea3b53c71e8

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top