2012-09-13 10 views
7

Ich weiß, wie man ein Doppelklick- und ein Zweifingerberührungsereignis erkennt, aber wie kann ich diese kombinieren, um zu reagieren, damit jemand mit zwei Fingern doppelklicken muss?Wie implementiert man einen Zwei-Finger-Doppelklick in Android?

Standardmäßig hat Android die lange drücken, um als eine zweite Form des Klickens zu fungieren, aber ich bin speziell auf der Suche nach einem Zwei-Finger-Doppelklick.

Antwort

14

wollte ich eine einfache und wiederverwendbare Schnittstelle, die für zwei Finger Doppelhähne und Beh hört Aves wie GestureDetector. Damit Sie es so verwenden könnte (alle schneiden & Paste runnable code):

public class Example extends Activity { 
    SimpleTwoFingerDoubleTapDetector multiTouchListener = new SimpleTwoFingerDoubleTapDetector() { 
     @Override 
     public void onTwoFingerDoubleTap() { 
      // Do what you want here, I used a Toast for demonstration 
      Toast.makeText(Example.this, "Two Finger Double Tap", Toast.LENGTH_SHORT).show(); 
     } 
    }; 

    // Override onCreate() and anything else you want 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     if(multiTouchListener.onTouchEvent(event)) 
      return true; 
     return super.onTouchEvent(event); 
    } 
} 

I SimpleTwoFingerDoubleTapDetector erstellt. (Es ist ein langer Name, aber es ist beschreibend Sie es als etwas umbenennen können Sie wollen..) Speichern Sie diese neue Datei in Ihrem Projekt oder als Bibliothek:

public abstract class SimpleTwoFingerDoubleTapDetector { 
    private static final int TIMEOUT = ViewConfiguration.getDoubleTapTimeout() + 100; 
    private long mFirstDownTime = 0; 
    private boolean mSeparateTouches = false; 
    private byte mTwoFingerTapCount = 0; 

    private void reset(long time) { 
     mFirstDownTime = time; 
     mSeparateTouches = false; 
     mTwoFingerTapCount = 0; 
    } 

    public boolean onTouchEvent(MotionEvent event) { 
     switch(event.getActionMasked()) { 
     case MotionEvent.ACTION_DOWN: 
      if(mFirstDownTime == 0 || event.getEventTime() - mFirstDownTime > TIMEOUT) 
       reset(event.getDownTime()); 
      break; 
     case MotionEvent.ACTION_POINTER_UP: 
      if(event.getPointerCount() == 2) 
       mTwoFingerTapCount++; 
      else 
       mFirstDownTime = 0; 
      break; 
     case MotionEvent.ACTION_UP: 
      if(!mSeparateTouches) 
       mSeparateTouches = true; 
      else if(mTwoFingerTapCount == 2 && event.getEventTime() - mFirstDownTime < TIMEOUT) { 
       onTwoFingerDoubleTap(); 
       mFirstDownTime = 0; 
       return true; 
      } 
     }    

     return false; 
    } 

    public abstract void onTwoFingerDoubleTap(); 
} 

Zunächst ein paar Notizen über Android (ein- touch) GestureDetector:

  • Android onDoubleTap() Ereignis verwendet ein Standard-Timeout-Wert von ViewConfiguration. Ich beziehe mich auf die gleiche Zeit.
  • Sie messen die verstrichene Zeit vom ersten Fingertiefereignis des ersten Tap bis zum Fingertiefereignis des zweiten Tap und senden dann onDoubleTap() und onDoubleTapEvent().
    • onDoubleTap() wird nur ausgelöst, wenn das Finger-Down-Ereignis des zweiten Tap auftritt.
    • onDoubleTapEvent() wird für jede Aktion durch den zweiten Tipp ausgelöst: nach unten, bewegen, und nach oben.

Ein paar Anmerkungen zu SimpleTwoFingerDoubleTapDetector:

  • ist mein Timeout von dem ersten Finger-Down-Ereignisse der letzten Finger- up Ereignis gemessen falsch Doppeltippen Benachrichtigungen zu verhindern . Ich habe dem Standard-ViewConfiguration-Double-Tap-Timeout etwas mehr Zeit hinzugefügt, um dies zu berücksichtigen.
  • Android GestureDetector misst slop (wie weit auseinander die beiden Taps sind). Ich habe die Notwendigkeit dafür hier nicht gesehen, noch habe ich den Abstand zwischen den zwei Fingern an jedem Hahn überprüft.
  • Ich sende nur ein Ereignis onTwoFingerDoubleTap().

Abschließender Hinweis: können Sie leicht ändern diese wie ein OnTouchListener verhalten:

  1. ändern SimpleTwoFingerDoubleTapDetector Definition:

    public abstract class SimpleTwoFingerDoubleTapListener implements OnTouchListener { 
    
  2. hinzufügen neue Klassenvariable:

    private View mFirstView; 
    
  3. Ändern der ACTION_DOWN Fall:

    case MotionEvent.ACTION_DOWN: 
        if(mFirstDownTime == -1 || mFirstView != v || hasTimedOut(event.getEventTime())) { 
         mFirstView = v; 
         reset(event.getDownTime()); 
        } 
        break; 
    
  4. Pass mFirstView innerhalb des ACTION_UP Fall:

    onTwoFingerDoubleTap(mFirstView); 
    
  5. Last, ändern Sie die onTwoFingerDoubleTap() Methode zu reflektieren, welche Ansicht wurde angezapft:

    public abstract void onTwoFingerDoubleTap(View v); 
    
+0

Diese Antwort ist großartig! – dowi

+2

Ich habe diesen Code ausprobiert (danke!) Und es hat nicht funktioniert - ich habe nur ACTION_DOWN-Ereignisse bekommen. Ich glaube, dass die onTouchEvent() Funktion True (für ACTION_DOWN) zurückgeben muss oder andernfalls ACTION_UP wird nicht danach empfangen. Siehe: http://StackOverflow.com/a/16495363/1277048 – FuzzyAmi

1

Dies ist ein Doppelklick-Listener, den ich erstellt habe, um einen Doppelklick mit zwei Fingern zu erkennen.

Variablen verwendet:

private GestureDetector gesture; 
private View.OnTouchListener gestureListener; 
boolean click1 = false; 
boolean click2 = false; 
long first = 0; 
long second = 0; 

In der onCreate() Aktivität die Berührungsereignisse registrieren:

gesture = new GestureDetector(getApplicationContext(), new SimpleOnGestureListener(){ 
    public boolean onDown(MotionEvent event) { 
     return true; 
    } 
}); 
gestureListener = new View.OnTouchListener() { 
    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
     return gesture.onTouchEvent(event); 
    } 
}; 

Außerhalb onCreate() innerhalb der Aktivität:

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    try { 
     int action = event.getAction() & MotionEvent.ACTION_MASK; 
     //capture the event when the user lifts their fingers, not on the down press 
     //to make sure they're not long pressing 
     if (action == MotionEvent.ACTION_POINTER_UP) { 
      //timer to get difference between clicks 
      Calendar now = Calendar.getInstance(); 

      //detect number of fingers, change to 1 for a single-finger double-click, 3 for a triple-finger double-click, etc. 
      if (event.getPointerCount() == 2) { 
       if (!click1) { 
        //if this is the first click, then there hasn't been a second 
        //click yet, also record the time 
        click1 = true; 
        click2 = false; 
        first = now.getTimeInMillis(); 
       } else if (click1) { 
        //if this is the second click, record its time 
        click2 = true; 
        second = now.getTimeInMillis(); 

        //if the difference between the 2 clicks is less than 500 ms (1/2 second) 
        //Math.abs() is used because you need to be able to detect any sequence of clicks, rather than just in pairs of two 
        //(e.g. click1 could be registered as a second click if the difference between click1 and click2 > 500 but 
        //click2 and the next click1 is < 500) 
        if (Math.abs(second-first) < 500) { 

         //do something!!!!!! 

        } else if (Math.abs(second-first) >= 500) { 
         //reset to handle more clicks 
         click1 = false; 
         click2 = false; 
        } 
       } 
      } 
     } 
    } catch (Exception e){ 

    } 
    return true; 
} 
+0

funktioniert nur einmal zum ersten Mal. – Nezam

+0

'if (click1 && click2 && Math.abs (zweit-erste) <500) {...}' ist zu viel. Sie können nicht zu diesem bestimmten Teil des Codes gelangen, es sei denn, 'click1 && click2' ist bereits wahr. Um hierher zu gelangen, musst du folgendes durchgehen: 'if (click1) {click2 = true; ...} '. Der gleiche Effekt kann mit 'if (Math.abs (second-first) <500) {// tue etwas !!!!!! } sonst {click1 = false; click2 = false;} ' –

+0

@Nezam Ich habe diesen Code seit Jahren nicht mehr benutzt, aber ich bin mir nicht sicher, warum das sein würde - es funktionierte in unserer App ganz gut – WOUNDEDStevenJones