Question

J'utilise la méthode OnScroll de GestureDetector.SimpleOnGestureListener pour faire défiler un grand bitmap sur une toile. Lorsque le rouleau est terminé, je veux redessiner le bitmap dans le cas où l'utilisateur souhaite faire défiler plus loin ... le bord du bitmap, mais je ne vois pas comment détecter lorsque le défilement est terminé (l'utilisateur a levé son doigt à partir de l'écran).

e2.getAction () semble toujours retourner la valeur 2 de sorte que l'aide est pas. e2.getPressure semble renvoyer des valeurs assez constantes (environ 0,25) jusqu'à ce que l'appel OnScroll finale lorsque la pression semble tomber à environ 0,13. Je suppose que je pouvais détecter cette diminution de la pression, mais ce sera loin d'être à toute épreuve.

Il doit y avoir une meilleure façon: quelqu'un peut-il aider, s'il vous plaît

Était-ce utile?

La solution

Voici comment je l'ai résolu le problème. Espérons que cela aide.

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

Autres conseils

Vous devriez jeter un oeil à http://developer.android.com /reference/android/widget/Scroller.html . Surtout cela pourrait être utile (triés par pertinence):

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

Cela implique que vous devez créer un Scroller.

Si vous voulez utiliser touchant vous pouvez également utiliser GestureDetector et définir votre propre défilement de la toile. L'exemple suivant crée un ScrollableImageView et pour l'utiliser, vous devez définir les mesures de votre image. Vous pouvez définir votre propre plage de défilement et après avoir terminé votre défilement l'image est redessinée.

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

En fonction de votre code, vous devriez envisager d'annuler (int l, int t, int r, int b); pour l'infirmation.

SimpleOnGestureListener.onFling() 

Il semble avoir lieu quand une des extrémités de défilement (à savoir l'utilisateur permet le déplacement du doigt), c'est ce que je me sers et il fonctionne très bien pour moi.

Pour revenir à ce après quelques mois, je l'ai maintenant suivi une approche différente: à l'aide d'un gestionnaire (comme dans l'exemple Serpent Android) pour envoyer un message à l'application toutes les 125 millisecondes qui incite à vérifier si un défilement a été commencé et si plus de 100 millisecondes se sont écoulées depuis le dernier événement de défilement.

Cela semble fonctionner assez bien, mais si quelqu'un peut voir des inconvénients ou des améliorations possibles, je serais reconnaissant d'entendre d'eux.

Le code correspondant est dans la 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;

// défilement est terminée, donc insérer le code ici

// qui appelle la méthode doDrawing ()

// pour redessiner recentrée où défilement bitmap terminé

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

// code pour dessiner un grand bitmap tampon sur la toile de la vue // positionné pour tenir compte de toute défilement qui est en cours

}

public void doDrawing() {

// code pour faire détaillé (et de temps) dessin // sur une grande bitmap tampon

// l'instruction suivante remet à zéro l'heure horloge de vérification // l'horloge est d'abord commencé quand // l'activité principale appelle cette méthode lorsque l'application démarre

        mTimeCheckHandler.sleep(timeCheckInterval);
}

// reste de la classe MyView

}

et dans la 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'instruction suivante provoque onDraw de la vue la méthode à appeler // qui trace le bitmap tampon sur l'écran // déplacé pour tenir compte du défilement

    [MyView].invalidate();

}

// reste de la classe MyGestureDetector

}

Je regardais dans ce même problème. J'ai vu réponse Akos Cz à votre question. J'ai créé quelque chose de similaire, mais avec ma version, j'ai remarqué que cela ne fonctionnait pour un défilement régulier - ce qui signifie celui qui ne génère pas une aventure. Mais si un Fling a réussi à avoir généré - peu importe si j'ai traité une aventure ou non, il n'a pas détecté le « ACTION_UP » dans « onTouchEvent ». Maintenant, peut-être c'était juste quelque chose avec ma mise en œuvre, mais si elle était je ne pouvais pas comprendre pourquoi.

Après une enquête plus approfondie, je remarquai que lors d'une aventure, le « ACTION_UP » a été adoptée dans « onFling » dans « e2 » à chaque fois. Donc, je pensais que doit être la raison pour laquelle il n'a pas été traitée dans « onTouchEvent » dans ces cas.

Pour le faire fonctionner pour moi je ne devais appeler une méthode pour gérer la « ACTION_UP » dans « onFling » et cela a fonctionné pour les deux types de défilement. Voici les étapes exactes que j'ai prises pour mettre en œuvre dans mon application:

-initialized un booléen "gestureScrolling" à "false" dans un constructeur.

-Je le mettre à "true" dans "OnScroll"

-Création une méthode pour gérer l'événement « ACTION_UP ». A l'intérieur de cet événement, je remis à zéro « gestureSCrolling » false puis a fait le reste du traitement que je devais faire.

-in "onTouchEvent", si un "ACTION_UP" a été détectée et "gestureScrolling" = true, alors j'ai appelé ma méthode pour gérer "ACTION_UP"

-Et la partie que je l'ai fait était différent était:. J'ai aussi appelé ma méthode pour gérer « ACTION_UP » à l'intérieur de « onFling »

Je suis sûr qu'il est trop tard pour vous, cependant, il semble que j'ai trouvé la bonne solution à votre question initiale et non nécessaire l'intention.

Si vous utilisez l'objet Scroller / OverScroller pour vous défilement devriez vérifier la valeur de retour de la fonction suivante.

public boolean computeScrollOffset() 

profiter

Harvinder

est ce qui a fonctionné pour moi.

Je l'ai enrichi la méthode existante GestureDetector.OnGestureListener onFingerUp () . Cet auditeur fait tout comme intégré GestureDetector et il peut également écouter l'événement doigt vers le haut (il n'est pas onFling () car cela est appelé uniquement lorsque le doigt est soulevé le long d'une action de balayage rapide).

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

Je ne l'ai pas fait moi-même, mais en regardant OnTouch () vous obtenez toujours une séquence 0 <2> 1, donc la fin doit être 1 pour ascenseur doigt.

Je ne sais pas Android, mais en regardant la documentation, il semble Rob a raison: Android ACTION_UP constante Essayez de vérifier pour ACTION_UP de getAction ()?

Edit: Qu'est-ce que e1.getAction () montrer? Est-il revenir jamais ACTION_UP? La documentation indique qu'il tient l'événement initial vers le bas, alors peut-être il va également informer lorsque le pointeur est jusqu'à

Edit: Plus que deux choses que je peux penser. Retournez-vous de faux à tout moment? Cela peut empêcher ACTION_UP

La seule autre chose que je vais essayer est d'avoir un événement séparé, peut-être onDown, et définir un indicateur dans les OnScroll tels que isScrolling. Lorsque ACTION_UP est donnée à onDown et isScrolling est réglé, vous pouvez faire ce que vous voulez et réinitialiser isScrolling false. Autrement dit, en supposant onDown est appelée ainsi OnScroll et getAction retournera ACTION_UP pendant onDown

Je ne l'ai pas essayé cette / utilisé, mais l'idée d'une approche:

Arrêt / interruption toile redessinant sur chaque événement de défilement attendre 1 et puis commencer toile redessiner à CHAQUE défilement.

cela conduira à réaliser le redessiner seulement à la fin de défilement que seul le dernier défilement sera effectivement sans interruption pour le redessiner pour terminer.

espérons que cette idée vous aide:)

Extrait de l'événement OnScroll de l'API GestureListener: lien texte

  

public abstract boolean OnScroll   (MotionEvent e1, e2 MotionEvent, flotteur   distanceX, flotter distanceY) depuis: API   Niveau 1

     

Retours       * True si l'événement est consommé, sinon false

Peut-être une fois que l'événement a été consommé, l'action est terminée et que l'utilisateur a pris son doigt de l'écran ou au moins terminé cette action OnScroll

Vous pouvez ensuite utiliser dans une instruction IF pour rechercher == true puis commencer par l'action suivante.

Je pense que cela fonctionnera comme vous avez besoin

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

}

Ma tentative d'ajouter des fonctionnalités supplémentaires à détecteur de mouvement. Il aide quelqu'un espère mettre son temps à mieux utiliser ...

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top