webentwicklung-frage-antwort-db.com.de

Android: Erkennen, wann ein Bildlauf beendet ist

Ich verwende die onScroll-Methode von GestureDetector.SimpleOnGestureListener, um eine große Bitmap auf einer Leinwand zu scrollen. Wenn das Scrollen beendet ist, möchte ich die Bitmap neu zeichnen, falls der Benutzer weiter scrollen möchte ... vom Rand des Bitmaps, aber ich kann nicht erkennen, wann das Scrollen beendet ist (der Benutzer hat seinen Finger angehoben) vom Bildschirm).

e2.getAction () scheint immer den Wert 2 zurückzugeben, sodass es keine Hilfe gibt. _2. e2.getPressure scheint bis zum letzten Aufruf von onScroll ziemlich konstante Werte (um 0,25) zurückzugeben, wenn der Druck auf etwa 0,13 fällt. Ich vermute, ich könnte diesen Druckabfall feststellen, aber das ist alles andere als sicher.

Es muss einen besseren Weg geben: Kann jemand helfen, bitte?

64
prepbgg

So habe ich das Problem gelöst. Hoffe das hilft.

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

Sie sollten einen Blick auf http://developer.Android.com/reference/Android/widget/Scroller.html ..__ werfen. Insbesondere dies könnte hilfreich sein (nach Relevanz sortiert):

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

Dies bedeutet, dass Sie einen Scroller erstellen müssen.

Wenn Sie Berührungen verwenden möchten, können Sie auch GestureDetector verwenden und Ihren eigenen Bildlauf definieren. Das folgende Beispiel erstellt ein ScrollableImageView. Damit Sie es verwenden können, müssen Sie die Maße Ihres Bildes definieren. Sie können Ihren eigenen Bildlaufbereich definieren und nach dem Bildlauf wird das Bild neu gezeichnet. 

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

Abhängig von Ihrem Code sollten Sie es für ungültig erklären (int l, int t, int r, int b); für die Ungültigerklärung.

4
user238801
SimpleOnGestureListener.onFling() 

Es scheint zu geschehen, wenn eine Schriftrolle endet (d. H. Der Benutzer lässt den Finger los), das verwende ich und es funktioniert gut für mich.

3
Aron Cederholm

Nach einigen Monaten habe ich nun einen anderen Ansatz verfolgt: Mit einem Handler (wie im Android-Snake-Beispiel) senden Sie alle 125 Millisekunden eine Nachricht an die App, in der Sie gefragt werden, ob ein Scroll gestartet wurde ob seit dem letzten Bildlaufereignis mehr als 100 Millisekunden vergangen sind.

Das scheint ziemlich gut zu funktionieren, aber wenn jemand irgendwelche Nachteile oder mögliche Verbesserungen sehen kann, wäre ich dankbar, von ihnen zu hören.

Der relevante Code befindet sich in der MyView-Klasse:

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;

// Scroll ist beendet, geben Sie den Code hier ein

// Welches ruft die Methode doDrawing () auf

// um das Bitmap neu zu zentrieren, wo der Bildlauf endete

                    [ 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 zum Zeichnen einer großen Pufferbitmap in den Canvas-Bereich der Ansicht//, die so positioniert ist, dass eine laufende Bildlaufleiste berücksichtigt wird

}

public void doDrawing() {

// Code zum ausführlichen (und zeitaufwendigen) Zeichnen// in eine große Pufferbitmap

// Die folgende Anweisung setzt die Zeitprüfungsuhr zurück. Die Uhr wird zuerst gestartet, wenn // die Hauptaktivität diese Methode aufruft, wenn die App startet

        mTimeCheckHandler.sleep(timeCheckInterval);
}

// Rest der MyView-Klasse

und in der MyGestureDetector-Klasse

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;

// Die nächste Anweisung bewirkt, dass die onDraw-Methode von View aufgerufen wird//, die die Pufferbitmap auf dem Bildschirm darstellt// verschoben, um die Bildlauffunktion zu berücksichtigen

    [MyView].invalidate();

}

// Rest der MyGestureDetector-Klasse

}

1
prepbgg

Ich habe das gleiche Thema untersucht. Ich habe gesehen, wie Akos Cz auf Ihre Frage antwortete. Ich habe etwas Ähnliches erstellt, aber bei meiner Version fiel mir auf, dass es nur für ein normales Scrollen funktionierte - was bedeutet, dass kein Fling erzeugt wird. Wenn jedoch ein Fling generiert wurde - unabhängig davon, ob ich einen Fling verarbeitet habe oder nicht, hat er das "ACTION_UP" in "onTouchEvent" NICHT erkannt. Vielleicht war das nur etwas mit meiner Implementierung, aber wenn es so wäre, könnte ich nicht verstehen, warum.

Nach weiteren Untersuchungen bemerkte ich, dass während eines Fluges jedes Mal "ACTION_UP" in "onFling" in "e2" übergeben wurde. Ich dachte mir, dass dies der Grund sein muss, warum es in diesen Fällen nicht in "onTouchEvent" behandelt wurde.

Damit es für mich funktioniert, musste ich nur eine Methode aufrufen, um das "ACTION_UP" in "onFling" zu behandeln, und dann funktionierte es für beide Arten des Bildlaufs. Im Folgenden sind die genauen Schritte zur Implementierung in meiner App aufgeführt:

-initialisierte einen boolean "gestureScrolling" in einem Konstruktor auf "false".

-Ich habe es in "onScroll" auf "true" gesetzt

-Erstelle eine Methode, um das Ereignis "ACTION_UP" zu behandeln. Innerhalb dieses Ereignisses setzte ich "GestureSCrolling" auf "false" zurück und erledigte dann den Rest der Verarbeitung, die ich durchführen musste.

-in "onTouchEvent", wenn ein "ACTION_UP" erkannt wurde und "gestureScrolling" = true ist, dann habe ich meine Methode aufgerufen, um "ACTION_UP" zu behandeln.

Und der Teil, den ich gemacht habe, war anders: Ich habe auch meine Methode aufgerufen, um "ACTION_UP" innerhalb von "onFling" zu behandeln.

1
Mike

Das hat bei mir funktioniert. 

Ich habe die vorhandene GestureDetector.OnGestureListener mit onFingerUp () - Methode angereichert. Dieser Listener führt alles als eingebauter GestureDetector aus und kann auch das Finger-Up-Ereignis abhören (es ist nicht onFling (), da dies nur aufgerufen wird, wenn der Finger zusammen mit einer schnellen Wischaktion angehoben wird).

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

Ich bin sicher, es ist zu spät für Sie, aber ich habe die richtige Lösung für Ihre ursprüngliche Frage gefunden und nicht die Absicht.

Wenn Sie Scroller/OverScroller-Objekt zum Scrollen verwenden, sollten Sie den Rückgabewert der folgenden Funktion überprüfen.

public boolean computeScrollOffset() 

genießen

harvinder

1
resp78

Ich denke, das funktioniert so, wie Sie es brauchen

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

}
0
nautilusvn

Mein Versuch, dem Gesten-Detektor zusätzliche Funktionen hinzuzufügen. Ich hoffe es hilft jemandem, seine Zeit besser zu nutzen ...

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

0
Peter

Ich habe das nicht selbst gemacht, aber bei onTouch () bekommst du immer eine Sequenz 0 <2> 1, also muss das Ende eine 1 sein, um den Finger zu heben.

0
Rob Kent

Auszug aus dem onScroll-Ereignis aus der GestureListener-API: Linktext

public abstract boolean onScroll (MotionEvent e1, MotionEvent e2, float DistanceX, float distanceY) Seit: API Level 1

Kehrt zurück * true, wenn das Ereignis belegt ist, sonst false

Wenn das Ereignis einmal abgeschlossen ist, ist die Aktion beendet, und der Benutzer hat den Finger vom Bildschirm genommen oder zumindest diese Aktion von onScroll beendet

Sie können dies dann in einer IF-Anweisung verwenden, um nach == true zu suchen und dann mit der nächsten Aktion zu beginnen.

0

Ich kenne Android nicht, aber wenn ich mir die Dokumentation ansehe, scheint Rob recht zu haben: Android ACTION_UP konstant Versuchen Sie es mit ACTION_UP von getAction ()?

Bearbeiten: Was zeigt e1.getAction ()? Gibt es jemals ACTION_UP zurück? Die Dokumentation besagt, dass das anfängliche Abwärtsereignis festgehalten wird. Möglicherweise wird es auch benachrichtigt, wenn der Zeiger oben ist

Edit: Nur zwei weitere Dinge fallen mir ein. Kommst du irgendwann falsch zurück? Das kann ACTION_UP verhindern

Die einzige andere Sache, die ich versuchen würde, ist, ein separates Ereignis zu haben, vielleicht onDown, und ein Flag in onScroll zu setzen, wie z. B. isScrolling. Wenn ACTION_UP an onDown übergeben wird und isScrolling festgelegt ist, können Sie tun, was Sie möchten, und isScrolling auf false zurücksetzen. Angenommen, onDown wird zusammen mit onScroll aufgerufen, und getAction gibt ACTION_UP während onDown zurück

0
Bob

ich habe es nicht ausprobiert, sondern eine Idee für einen Ansatz:

Stoppen/Unterbrechen des Neuzeichnens der Leinwand bei JEDEM Bildlaufereignis warten Sie 1s und beginnen Sie dann beim Neuzeichnen der Leinwand bei JEDEM Bildlauf.  

dies führt dazu, dass das Neuzeichnen nur am Bildlaufende ausgeführt wird, da nur der letzte Bildlauf tatsächlich ununterbrochen ist, damit das Neuzeichnen abgeschlossen werden kann.

hoffe diese idee hilft dir :)

0
b0x0rz