web-dev-qa-db-fra.com

Impossible de gérer simultanément les événements clic et tactile

J'essaie de gérer des événements tactiles et de cliquer sur des événements sur un bouton. Je fais ce qui suit:

button.setOnClickListener(clickListener);
button.setOnTouchListener(touchListener);

Lorsqu'un auditeur est enregistré, tout fonctionne correctement, mais lorsque j'essaie de les utiliser, seuls les événements tactiles sont déclenchés. Une solution de contournement? Qu'est-ce que je fais mal?

40
Ragunath Jawahar

Il existe une différence subtile mais très importante entre ClickListener et TouchListener. La TouchListener est exécutée avant que la vue puisse répondre à l'événement. La ClickListener ne recevra son événement que lorsque la vue l'aura traité.

Ainsi, lorsque vous touchez votre écran, la TouchListener est exécutée en premier et lorsque vous renvoyez true pour votre événement, la ClickListener ne l'obtiendra jamais. Mais si vous appuyez sur la boule de commande de votre appareil, la ClickListener doit être déclenchée, car la TouchListener ne répond pas.

38
Chris

C'est un peu délicat.

Si vous définissez onTouchListener, vous devez renvoyer true dans ACTION_DOWN, pour indiquer au système que j'ai consommé l'événement et qu'il ne sera pas répercuté sur les autres écouteurs.

Mais alors OnClickListener ne sera pas renvoyé.

Vous pouvez donc penser que je vais juste faire mon travail là-bas et renvoyer false afin que je puisse aussi recevoir des clics . Si vous le faites, cela fonctionnera, mais vous ne serez pas abonné à d'autres événements tactiles à venir (ACTION_MOVE, ACTION_UP ) Par conséquent, la seule option consiste à renvoyer true à cet endroit, mais vous ne recevrez aucun événement de clic comme indiqué précédemment.

Vous devez donc effectuer le clic manuellement dans le ACTION_UP avec view.performClick()

Cela fonctionnera.

66
urSus

Vous devriez retourner false dans votre OnTouchListener, votre OnClickListener sera également traitée.

5
Yvan RAJAONARIVONY

Je suppose que vous retournez true dans votre OnTouchListener? Cela consommera l'événement, il ne sera donc pas envoyé pour un traitement ultérieur.

Sur une note de côté - quel est l'intérêt d'avoir à la fois un écouteur clic et tactile?

5
EboMike
button.setOnTouchListener(this);

Implémentez l'interface et le code ici:

@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
    switch (view.getId()) {
        case R.id.send:
            switch(motionEvent.getAction()){
                case MotionEvent.ACTION_DOWN:
                    //when the user has pressed the button
                    //do the needful here
                    break;
                case MotionEvent.ACTION_UP:
                    //when the user releases the button
                    //do the needful here
                    break;
            }
            break;
    }
    return false;
}
0
Geet Choubey
## Exact working solution for both click action and touch listener(dragging) ##

private int initialX;
private int initialY;
private float initialTouchX;
private float initialTouchY;
private float CLICK_ACTION_THRESHOLD = 0.5f;
private float startX;
private float startY;

 @Override
public boolean onTouch(View view, MotionEvent event) {
    switch (view.getId()) {
        case R.id.chat_head_profile_iv:
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    //remember the initial position.
                    initialX = params.x;
                    initialY = params.y;
                    startX = event.getX();
                    startY = event.getY();
                    //get the touch location
                    initialTouchX = event.getRawX();
                    initialTouchY = event.getRawY();
                    return true;
                case MotionEvent.ACTION_UP:
                    float endX = event.getX();
                    float endY = event.getY();
                    if (shouldClickActionWork(startX, endX, startY, endY)) {
                        openScreen();// WE HAVE A CLICK!!
                    }
                    return true;
                case MotionEvent.ACTION_MOVE:
                    //Calculate the X and Y coordinates of the view.
                    params.x = initialX + (int) (event.getRawX() - initialTouchX);
                    params.y = initialY + (int) (event.getRawY() - initialTouchY);

                    //Update the layout with new X & Y coordinate
                    mWindowManager.updateViewLayout(mChatHeadView, params);
                    return true;
            }
            break;
    }
    return true;
}

private boolean shouldClickActionWork(float startX, float endX, float startY, float endY) {
    float differenceX = Math.abs(startX - endX);
    float differenceY = Math.abs(startY - endY);
    if ((CLICK_ACTION_THRESHOLD > differenceX) && (CLICK_ACTION_THRESHOLD > differenceY))
        return true;
    else
        return false;
}
0
manas.abrol

Pour rendre les deux événements possibles dans gridview, uniquement en rendant le retour de l'auditeur tactile "faux" comme suit, cela a fonctionné pour moi.

**GridView myView = findViewById(R.id.grid_view);
myView.setOnTouchListener(new OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) {
        // ... Respond to touch events
        return false;
    }
});**

de cette façon, les deux événements peuvent être atteints

0
amyShamna

Toutes les réponses ci-dessus sont dites que nous ne pouvons pas gérer à la fois setOnTouchListener et setOnClickListener.
Cependant, je vois que nous pouvons gérer les deux par return false dans setOnTouchListener

Exemple

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    button = findViewById(R.id.button)
    button.setOnClickListener {
        Log.i("TAG", "onClick")
    }

    button.setOnTouchListener { v, event ->
        Log.i("TAG", "onTouch " + event.action)
        false
    }
}

Lorsque je clique sur Button, logcat s’affiche comme suit:

I/TAG: onTouch 0
I/TAG: onTouch 1
I/TAG: onClick
0
Linh