web-dev-qa-db-fra.com

Comment détecter un clic dans un écouteur onTouch?

J'ai une ViewPager dans une ScrollView. Je dois pouvoir faire défiler horizontalement et verticalement. Pour ce faire, il fallait désactiver le défilement vertical chaque fois que ma ViewPager est touchée (v.getParent().requestDisallowInterceptTouchEvent(true);), afin de pouvoir le faire défiler horizontalement.

Mais en même temps, je dois pouvoir cliquer sur le viewPager pour l'ouvrir en mode plein écran.

Le problème est que onTouch est appelé avant onClick et mon OnClick n'est jamais appelé.

Comment puis-je mettre en œuvre à la fois sur une touche onClick tactile?

viewPager.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        System.out.println("TOUCHED ");
        if(event.getAction() == MotionEvent.???){
            //open fullscreen activity
        }
        v.getParent().requestDisallowInterceptTouchEvent(true); //This cannot be removed
        return false;
    }
});

viewPager.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        System.out.println("CLICKED ");
        Intent fullPhotoIntent = new Intent(context, FullPhotoActivity.class);
        fullPhotoIntent.putStringArrayListExtra("imageUrls", imageUrls);
        startActivity(fullPhotoIntent);
    }
});
19
code511788465541441

La réponse de Masoud Dadashi m'a aidé à comprendre.

voici à quoi cela ressemble à la fin.

viewPager.setOnTouchListener(new OnTouchListener() {
    private int CLICK_ACTION_THRESHOLD = 200;
    private float startX;
    private float startY;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            startX = event.getX();
            startY = event.getY();
            break;
        case MotionEvent.ACTION_UP: 
            float endX = event.getX();
            float endY = event.getY();
            if (isAClick(startX, endX, startY, endY)) { 
                launchFullPhotoActivity(imageUrls);// WE HAVE A CLICK!!
            }
            break;
        }
        v.getParent().requestDisallowInterceptTouchEvent(true); //specific to my project
        return false; //specific to my project
    }

    private boolean isAClick(float startX, float endX, float startY, float endY) {
        float differenceX = Math.abs(startX - endX);
        float differenceY = Math.abs(startY - endY);
        return !(differenceX > CLICK_ACTION_THRESHOLD/* =5 */ || differenceY > CLICK_ACTION_THRESHOLD);
    } 
}
55
code511788465541441

J'ai fait quelque chose de très simple en enregistrant l'heure à laquelle l'utilisateur touche l'écran.

private long lastTouchDown;
private static int CLICK_ACTION_THRESHHOLD = 200;

@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            lastTouchDown = System.currentTimeMillis();
            break;
        case MotionEvent.ACTION_UP:
            if (System.currentTimeMillis() - lastTouchDown < CLICK_ACTION_THRESHHOLD) {
                Log.w("App", "You clicked!");
            }
            break;
    }
    return true;
}

Il convient également de noter que GestureDetector intègre cette fonctionnalité. Regardez onSingleTapUp

17
nilsi

Développer les deux est la mauvaise idée. quand l'utilisateur peut faire différentes choses en touchant l'écran, comprendre que le but de l'utilisateur est un peu astucieux et que vous devez développer un morceau de code pour cela.

Deux solutions:

1- (meilleure idée) dans votre événement onTouch, vérifiez s'il y a une requête. Vous pouvez le faire en vérifiant s'il y a du mouvement en utilisant:

ACTION_UP
ACTION_DOWN
ACTION_MOVE

fais-le comme ça

if(event.getAction() != MotionEvent.ACTION_MOVE)

vous pouvez même vérifier la distance du mouvement du doigt de l'utilisateur à l'écran pour vous assurer qu'un mouvement s'est produit plutôt qu'un mouvement accidentel en cliquant. fais-le comme ça:

switch(event.getAction())
 {
     case MotionEvent.ACTION_DOWN:
              if(isDown == false)
              {
                     startX = event.getX();
                     startY = event.getY();
                     isDown = true;
              }
              Break;
        case MotionEvent.ACTION_UP
              {
                     endX = event.getX();
                     endY = event.getY();
                     break;
          }
}

considérez cela comme un clic si rien de ce qui précède ne s'est produit et faites ce que vous voulez faire avec clic.

2) Si vous jouez avec votre interface utilisateur, créez un bouton ou un bouton d’image ou un objet quelconque pour un filtrage complet, puis définissez un onClick.

Bonne chance

9
Masoud Dadashi

Vous devrez peut-être faire la distinction entre les clics utilisateur et les clics longs. Sinon, vous détecterez les deux comme étant la même chose. J'ai fait cela pour rendre cela possible:

@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        startX = event.getX();
        startY = event.getY();

        bClick = true;
        tmrClick = new Timer();
        tmrClick.schedule(new TimerTask() {
            public void run() {
                if (bClick == true) {
                    bClick = false;
                    Log.d(LOG_TAG, "Hey, a long press event!");
                    //Handle the longpress event.
                }
            }
        }, 500); //500ms is the standard longpress response time. Adjust as you see fit.

        return true;
    case MotionEvent.ACTION_UP:
        endX = event.getX();
        endY = event.getY();

        diffX = Math.abs(startX - endX);
        diffY = Math.abs(startY - endY);

        if (diffX <= 5 && diffY <= 5 && bClick == true) {
            Log.d(LOG_TAG, "A click event!");
            bClick = false;
        }
        return true;
    default:
        return false;
    }
}
5
Adam Komar

Je pense que la solution temps/position devrait être meilleure: 

 private float initialTouchX;
 private float initialTouchY;
 private long lastTouchDown;
 private static int CLICK_ACTION_THRESHHOLD = 100;
 @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:

                        lastTouchDown = System.currentTimeMillis();

                        //get the touch location
                        initialTouchX = event.getRawX();
                        initialTouchY = event.getRawY();
                        return true;
                    case MotionEvent.ACTION_UP:
                        int Xdiff = (int) (event.getRawX() - initialTouchX);
                        int Ydiff = (int) (event.getRawY() - initialTouchY);

                        if (System.currentTimeMillis() - lastTouchDown < CLICK_ACTION_THRESHHOLD &&  (Xdiff < 10 && Ydiff < 10))  {
                           //clicked!!!
                        }
                        return true;
                }
                return false;
            }
        });
1
Mihuilk

MotionEvent.ACTION_UP signifie que vous touchez l'heure du capteur

MotionEvent.ACTION_DOWN signifie que le capteur tactile ne détecte plus

par exemple, MotionEvent.ACTION_MOVE signifie que le capteur détecte certains mouvements (tels que le balayage, le défilement, etc.)

il vous suffit donc de sauvegarder l'état du type d'événement précédent dans votre écouteur et de le comparer avec le dernier événement pour comprendre ce que l'utilisateur a fait.

Chaque vue couvre son parent. Donc, si votre vue a un écouteur tactile, cela fonctionne comme un intercepteur. Il est possible de continuer la chaîne d'appels tactiles aux vues parent renvoyant la valeur false par la méthode boolean onTouch (View v, événement MotionEvent).

additional: View.performClick () ne renvoie true que s'il dispose de OnClickListener

yourView.setOnTouchListener(new View.OnTouchListener() {
                int lastEvent;
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (event.getAction() == MotionEvent.ACTION_UP && lastEvent == MotionEvent.ACTION_DOWN) {
                        return ~ /**Click detected. Do something and return result**/
                    }
                    lastEvent = event.getAction();
                    return v.performClick();
                }
            });
0
Oleg Bozhko

Je crois que vous empêchez votre vue de recevoir l'événement tactile de cette manière car votre TouchListener l'intercepte . Vous pouvez soit

  • Envoyez l'événement à l'intérieur de votre ToucheListener en appelant v.onTouchEvent(event)
  • Remplacer à la place ViewPager.onTouchEvent(MotionEvent) pour ne pas intercepter l'événement

De plus, renvoyer true signifie que vous n'avez pas consommé l'événement, que les événements suivants ne vous intéressent pas et que, par conséquent, vous ne recevrez pas les événements suivants tant que le geste n'est pas terminé (le doigt est à nouveau levé).

0
Antoine Marques

vous pouvez utiliser OnTouchClickListener

https://github.com/hoffergg/BaseLibrary/blob/master/src/main/Java/com/dailycation/base/view/listener/OnTouchClickListener.Java

usage:

view.setOnTouchListener(new OnTouchClickListener(new OnTouchClickListener.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //perform onClick
                }
            },5));

0
hoffer