2011-09-30 4 views
12

mam onLongPress i onDoubleTap działań umieszczonych na przycisk według tego kodu:Dlaczego android onLongPress zawsze jest uruchamiany po onDoubleTap?

... 
GestureDetector detector = new GestureDetector(this, new TapDetector()); 

public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
    detector = new GestureDetector(this, new TapDetector()); 
    ... 
} 

private class TapDetector extends GestureDetector.SimpleOnGestureListener { 

    @Override 
    public boolean onDoubleTap(MotionEvent e) { 
     // Do something 
     return true; 
    } 

    @Override 
    public void onLongPress(MotionEvent e) {   
     // Do something   
    } 
} 

Button incomeButton = (Button) findViewById(R.id.income); 
button.setOnTouchListener(new OnTouchListener(){ 
    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
     detector.onTouchEvent(event); 
     return true; 
    } 
}); 

zawsze widzę onLongPress zwolniony po onDoubleClick zwolniony i stracony. Jaki jest powód takich sprzecznych z intuicją zachowań i jak tego uniknąć?

AKTUALIZACJA ja zmieniłem kod źródłowy, aby być bardziej szczegółowe

public class MainActivity extends Activity { 
private GestureDetector detector; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
    detector = new GestureDetector(this, new TapDetector());  

    Button button = (Button) findViewById(R.id.button);     
    button.setOnTouchListener(new OnTouchListener(){ 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      System.out.println("************* onTouch *************"); 
      detector.onTouchEvent(event); 
      return true; 
     } 
    });       
}  

class TapDetector extends GestureDetector.SimpleOnGestureListener { 

    @Override 
    public void onLongPress(MotionEvent e) { 
     System.out.println("************* onLongPress *************");      
    }   

    @Override 
    public boolean onDoubleTap(MotionEvent e) { 
     System.out.println("************* onDoubleTap *************"); 
     Intent intent = new Intent();   
     intent.setClass(getApplicationContext(), NewActivity.class); 
     intent.putExtra("parameterName", "parameter"); 
     startActivity(intent);    
     return true; 
    }    
}   
} 

Jest to log po onDoubleTap kliknąłem. Możesz zobaczyć onLongPress na końcu - nigdy go nie klikam.

I/System.out(1106): ************* onTouch ************* 
I/System.out(1106): ************* onTouch ************* 
I/System.out(1106): ************* onTouch ************* 
I/System.out(1106): ************* onDoubleTap ************* 
I/ActivityManager( 59): Starting activity: Intent { cmp=my.tapdetector/.NewActivity (has extras) } 
I/ActivityManager( 59): Displayed activity my.tapdetector/.NewActivity: 324 ms (total 324 ms) 
I/System.out(1106): ************* onLongPress ************* 

UPDATE znalazłem rozwiązanie. Aby uniknąć onLongPress wypalania dwa zmiany należy zrobić:

pierwsze: detector.setIsLongpressEnabled (prawda); w onTouch (Zobacz przeciwko, wydarzenie MotionEvent)

button.setOnTouchListener(new OnTouchListener(){ 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      System.out.println("************* onTouch *************"); 
      detector.onTouchEvent(event); 
      detector.setIsLongpressEnabled(true); 
      return true; 
     } 
    }); 

drugie: dodać detector.setIsLongpressEnabled (fałszywy); w onDoubleTap (MotionEvent e)

 public boolean onDoubleTap(MotionEvent e) { 
     detector.setIsLongpressEnabled(false); 
     System.out.println("************* onDoubleTap *************"); 
     Intent intent = new Intent();   
     intent.setClass(getApplicationContext(), NewActivity.class); 
     intent.putExtra("parameterName", "parameter"); 
     startActivity(intent);    
     return true; 
    } 
+0

Nie mogę tego powtórzyć, przepraszam. Używając Log.i() w tych 2 zdarzeniach, są one wywoływane poprawnie. –

+0

Przyzwoita praca wokół tego, co wydaje się być wbudowanym warunkiem wyścigowym, jak opisano w komentarzach zaakceptowanej odpowiedzi. dzięki. –

Odpowiedz

3

Technicznie to nie powinno się zdarzyć

case MotionEvent.ACTION_DOWN: 
     mLastMotionX = x; 
     mLastMotionY = y; 
     mCurrentDownEvent = MotionEvent.obtain(ev); 
     mAlwaysInTapRegion = true; 
     mInLongPress = false; 

     if (mIsLongpressEnabled) { 
      mHandler.removeMessages(LONG_PRESS); 
      mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime() 
        + tapTime + longpressTime); 
     } 
     mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + tapTime); 

bo na razie ACTION_DOWN lub ACTION_UP, wszystkie komunikaty LONG_PRESS zdarzenia są usuwane z kolejki. Tak więc po drugim dotknięciu poniższy kod usunie długie zdarzenia prasowe.

mHandler.removeMessages(LONG_PRESS); 

Ninja edit: hacky obejście problemu

 @Override 
    public void onLongPress(MotionEvent e) { 
     if(MainActivity.this.hasWindowFocus()) 
     { 
      Log.d("Touchy", "Long tap");  
     } 
    } 
+1

Jak już znalazłem, zawsze korzystam z usługi LongPress uruchamianej po onDoubleTap ** tylko w debugerze **, jeśli punkt przerwania jest ustawiony na metodzie onDoubleClick. Jeśli usunę punkt kontrolny - wszystko jest w porządku ... – isabsent

+1

To ma sens, 'mCurrentDownEvent.getDownTime() + tapTime + longpressTime' wygasło przed tym terminem – Reno

+0

Wydaje się, że jeśli mam długi czas przetwarzania treści w metodzie onDoubleTap, zawsze otrzyma OnLongPress zwolniony? – isabsent

0

Widzisz zawsze onLongPress zwolniony, ponieważ w kodzie masz zamiar uruchomić przed spożywania zdarzenie onDoubleTap.
Możesz wyłączyć opcję Długie naciśnięcie przez
public void setIsLongpressEnabled (boolean isLongpressEnabled)
i użyć metody onDown w celu wykonania czynności.