2013-01-23 6 views
7

Ho una vista che è necessario elaborare gli eventi onTouch e onClick. Qual è il modo corretto per raggiungere questo obiettivo?Ricezione degli eventi onTouch e onClick con Android

Ho un onTouchListener e un onClickListener impostato sulla vista. Ogni volta che tocchi la vista, viene prima attivato l'evento onTouch e successivamente lo onClick. Tuttavia, dal gestore di eventi onTouch devo restituire true o false. Restituire true significa che l'evento si sta consumando, quindi il sistema di eventi Android non propagherà ulteriormente l'evento.

Pertanto, un evento onClick non viene mai generato, atleast mia onClick ascoltatore non viene mai attivato quando torno nel mio true gestore onTouch eventi. D'altra parte, restituendo false non c'è un'opzione, poiché ciò impedisce al listener onTouch di ricevere ulteriori eventi necessari per riconoscere un gesto. Qual è il solito modo di risolvere questo?

+1

Perché hai bisogno di suTouch AND onClick? Sicuramente solo onTouch sarebbe sufficiente. – JDx

+0

Che dire di [GestureDetector] (http://developer.android.com/reference/android/view/GestureDetector.html)? – keyser

+0

@JDx Come posso riconoscere un clic da un 'onTouchListener'? Un clic è una sequenza di almeno due eventi tattili, in cui l'evento 'ACTION_DOWN' viene generato nella stessa posizione (o almeno nella stessa vista) dell'evento successivo 'ACTION_UP'. Certo, si potrebbe implementare questo, e lo farò se non ci sarà altra soluzione. Ma la mia domanda è davvero, se esiste una soluzione integrata per questo scenario? – theV0ID

risposta

5

se si utilizza onTouchListener, non è necessario utilizzare onClickListener. in onClickListener quello che fa è ottenere l'evento touch e controllare le azioni dell'evento e rilevare il clic. quindi se vuoi fare un po 'di lavoro quando onClick. puoi farlo nel onTouchListener filtrando l'azione.

public boolean onTouch(View v, MotionEvent event) { 
if (event.getAction() == MotionEvent.ACTION_DOWN) { 
    //this is touch 

} 
if (event.getAction() == MotionEvent.ACTION_UP) { 
    //this is click 

} 
return false; 
} 
+0

È possibile attivare esplicitamente un evento 'onClick' dal blocco' MotionEvent.ACTION_UP'? – theV0ID

+0

E: cosa succede se la mia vista è in realtà un 'ViewGroup' e alcune delle sue viste secondarie devono ancora elaborare l'evento' onClick'? – theV0ID

+0

theV0ID, sì è possibile chiamando view.performClick(). –

0

Concordo con JDX, se si utilizza onTouchlistener non avete bisogno di usare onclicklistener e viceversa, se si vuole attivare un evento tasto, l'immagine, oppure fare clic su TextView, poi basta sparare onClicklistener. se vuoi animazioni come trascinamento e rotazione, usa ontouchlistener per ottenere le coordinate della superficie toccate

+0

Come già sottolineato: Cosa succede se la mia vista è in realtà un ViewGroup e alcune delle sue viste secondarie devono ancora elaborare l'evento onClick? – theV0ID

+0

Ci sono situazioni in cui è necessario avere un ascoltatore onclick e onuch. Generare un evento click all'interno da un onuch durante ACTION_UP non è la stessa cosa. – AndroidDev

6

In GestureDetector puoi chiamare direttamente callOnClick(). Nota l'API View.callOnClick richiede il livello API 15. Basta provare.

// Create a Gesturedetector 
GestureDetector mGestureDetector = new GestureDetector(context, new MyGestureDetector()); 

// Add a OnTouchListener into view 
m_myViewer.setOnTouchListener(new OnTouchListener() 
{ 

    @Override 
    public boolean onTouch(View v, MotionEvent event) 
    { 
     return mGestureDetector.onTouchEvent(event); 
    } 
}); 

private class MyGestureDetector extends GestureDetector.SimpleOnGestureListener 
{ 
    public boolean onSingleTapUp(MotionEvent e) { 
     // ---Call it directly--- 
     callOnClick(); 
     return false; 
    } 

    public void onLongPress(MotionEvent e) { 
    } 

    public boolean onDoubleTap(MotionEvent e) { 
     return false; 
    } 

    public boolean onDoubleTapEvent(MotionEvent e) { 
     return false; 
    } 

    public boolean onSingleTapConfirmed(MotionEvent e) { 
     return false; 

    } 

    public void onShowPress(MotionEvent e) { 
     LogUtil.d(TAG, "onShowPress"); 
    } 

    public boolean onDown(MotionEvent e) {    
     // Must return true to get matching events for this down event. 
     return true; 
    } 

    public boolean onScroll(MotionEvent e1, MotionEvent e2, final float distanceX, float distanceY) { 
     return super.onScroll(e1, e2, distanceX, distanceY); 
    }   

    @Override 
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 
     // do something 
     return super.onFling(e1, e2, velocityX, velocityY); 
    } 
} 
+0

Dove è definito il metodo 'callOnClick'? Non riesco a trovarlo nell'API, né in quelli di 'SimpleOnGestureListener' né in quelli di 'GestureDetector'. – theV0ID

+0

L'API View.callOnClick richiede il livello API 15. Puoi trovarlo: http: //developer.android.com/intl/zh-CN/reference/android/view/View.html#callOnClick(). SimpleOnGestureListener esteso da GestureDetector.OnGestureListener, è possibile trovarlo in http://developer.android.com/intl/zh-CN/reference/android/view/GestureDetector.SimpleOnGestureListener.html – Autobots

0
isMove = false; 
case MotionEvent.ACTION_DOWN: 
//Your stuff 
isMove = false; 
case MotionEvent.ACTION_UP: 
if (!isMove || (Xdiff < 10 && Ydiff < 10) { 
view.performClick; //The check for Xdiff <10 && YDiff< 10 because sometime elements moves a little 
even when you just click it 
} 
case MotionEvent.ACTION_MOVE: 
isMove = true; 

Un altro modo è quello di utilizzare fili. Ovvero su Action_Down inizia una discussione per incrementare un contatore. In caso di Action_UP: interrompe/interrompe il thread. cercare contatore se è inferiore a 2 (diciamo o soglia secondo la vostra applicazione) o! isMove poi richiamare la funzione click

4
@Override 
    public boolean onTouch(View v, MotionEvent event) { 


     switch (event.getAction()) { 
      case MotionEvent.ACTION_MOVE: 
       layOutParams.x = initialX + (int) (event.getRawX() - initialTouchX); 
       layOutParams.y = initialY + (int) (event.getRawY() - initialTouchY); 

       break; 
      case MotionEvent.ACTION_DOWN: 
       initialX = layOutParams.x; 
       initialY = layOutParams.y; 
       initialTouchX = event.getRawX(); 
       initialTouchY = event.getRawY(); 
       if (initialTouchX == event.getRawX() && initialTouchY == event.getRawY()) { 
        return false;// to handle Click 
       } 
       break; 
      case MotionEvent.ACTION_UP: 
       if (initialTouchX == event.getRawX() && initialTouchY == event.getRawY()) { 
        return false;// to handle Click 
       } 
       break; 

     } 
     return true; 

    } 
}; 
0

possiamo usare implementazione basata bandiera. dove scorrere/trascinare possiamo gestire in Action_Up e rendere il flag vero e restituire lo stesso. In caso di clic o tocca lo stesso handle in Action_Down e imposta il flag false e return.

touchAndSwipe=false; 
     switch(e.getAction()){ 
     case MotionEvent.ACTION_MOVE:    
      break; 
     case MotionEvent.ACTION_DOWN:    
      x1 = e.getX(); 
      break; 
     case MotionEvent.ACTION_UP: 
      x2 = e.getX(); 
      float diff= x2-x1; 
       if(Math.abs(delta)>100){ 
       // Swipe 
       touchAndSwipe=true; 
       }else{ 
       touchAndSwipe=false; 
        }    
      break; 
     } 
     return touchAndSwipe; 
0

Sono stato in grado di attuare Su clic e OnTouch insieme in una tastiera personalizzata che sto costruendo. Puoi dare un'occhiata a questo codice e modificarlo in base al tuo contesto, dal momento che non hai incluso un esempio di codice da cui lavorare.

Se pubblichi un esempio del tuo codice, posso modificare questo mio esempio per ottenere lo stesso risultato per il tuo utilizzo. Il contesto è tutto quando si parla di sviluppo Android. Dai un'occhiata a questo snippet di codice e controlla se è utile. Altrimenti pubblica un tuo esempio e apporterò le modifiche e risponderò.

 View DefaultphaseLay() { 

     LinearLayout mViewFirstPhase = (LinearLayout) getLayoutInflater().inflate(R.layout.layout_default_phase, parent); 

     ksOne_btn_LiLay = (LinearLayout) mViewFirstPhase.findViewById(R.id.ksOne_btn_LiLay); 
     ksOne_btn = (Button) mViewFirstPhase.findViewById(R.id.ksOne_btn); 
     ksOne_btn.setOnClickListener(mCorkyListener); 
     ksOne_btn.setFocusableInTouchMode(true); 
     ksOne_btn.setFocusable(true); 
     ksOne_btn.setOnTouchListener(new View.OnTouchListener() { 
      @Override 
      public boolean onTouch(View v, MotionEvent event) { 

       if (event.getAction() == MotionEvent.ACTION_DOWN) { 
        playClick(keyCode); 
        //v.startAnimation(animScale); 
        //key_sound.start(); 
        xkeys_lay.setVisibility(View.GONE); 
        numkeys_lay.setVisibility(View.GONE); 
        if (Constants.HapticFeedbackConstant) { 
         myVib.vibrate(Constants.vibration_duration); 
        } 
       } else if (event.getAction() == MotionEvent.ACTION_UP) { 
        ksOne_btn.setFocusable(false); //Check This Added This In Attempt to Kill Selector on Action_Up 
        //playClick(-100); 
        //key_sound.pause(); 
       } 
       return false; 
      } 
     }); 

     ChangeKeyBackgroundMehods.initChange_Key_Background(ksOne_btn_LiLay); 
     ChangeFontStyle.initChange_fontStyle(ksOne_btn, getApplicationContext()); 
     ChangeFont_size.initChange_fontSize(ksOne_btn, getApplicationContext()); 

questo funziona per il contesto di tipo alfa o uscita numerica, se l'evento è in cerca di inviare o consumare qualche altro contesto avrebbe bisogno di essere modificato.

+0

Ecco un altro esempio utilizzando switch/case vs se/else se vedi sotto, ma se usi con alfa/numerico devi assicurarti di gestire gli stati e gli stati di shift premuti altrimenti finirai per ottenere caratteri doppi nel tuo output sui campi EditText. –