web-dev-qa-db-fra.com

Comment combiner OnClickListener et OnTouchListener pour un ImageButton

Je dois faire quelque chose lorsque l'utilisateur clique sur ImageButton J'ai essayé de créer une classe statique qui implémente both OnClickListener et OnTouchListener

static class ClickListenerForScrolling implements OnClickListener, OnTouchListener 

qui a les méthodes suivantes:

@Override
public void onClick(View v)

et 

@Override
public boolean onTouch(View arg0, MotionEvent arg1)

L'idée est de changer la source d'image de la ImageButton lorsque l'utilisateur la touche et d'effectuer une tâche lorsque l'utilisateur clique sur ce bouton. Quelqu'un peut-il me donner un indice sur la façon de procéder? 

22

Étant donné que les deux actions consistent en des gestes "mettre le doigt sur l'écran - lever le doigt de l'écran", vous ne pouvez pas déterminer s'il s'agit d'une action tactile ou d'une action de clic. Donc, si vous implémentez les deux écouteurs sur ce bouton d'image, un toucher/clic changera l'image ET appuiera sur le bouton. Pas sûr s'il y a un ordre déterminé de ces événements ...

Toutefois, si vous souhaitez séparer ces événements, vous devrez soit définir un geste différent de l'une des actions (comme effacer pour changer d'image), soit créer différentes zones qui gèrent les événements, par exemple, l'image ne s'adapte pas. le bouton entier et la zone libre servent de zone de clic sur le bouton.

HTH

Mettre à jour:

J'ai découvert qu'une TouchEvent est plus générale qu'une ClickEvent et qu'elle s'appelle donc en premier.

public abstract boolean onTouch (View v, MotionEvent event)

Ceci renvoie true, si le programme d'écoute a consommé l'événement, false sinon. Vous pouvez donc décider dans votre implémentation si l'événement doit également être géré par OnClickListener, puis renvoyez simplement false.

34
Sven Menschner

La onTouchListener est capable de gérer les deux mouvements.

Switch entre les valeurs event.action() pour obtenir MotionEvent.

case MotionEvent.ACTION_DOWN: est l'impact au premier doigt.
case MotionEvent.ACTION_UP: est le moment où le doigt s'en va. 

Vous devrez définir le point d'impact sur ACTION_DOWN.

TheImpactPoint=event.getX();

Et puis obtenir la distance avec ACTION_UP

float distance =TheImpactPoint-event.getX();

If distance = 0 alors il y a un clic, sinon ce serait plus ou moins que zéro en fonction du geste.

C'est donc la manière d'utiliser l'événement click sans événement click réel et en utilisant uniquement la variable onTouchListener.

L'espoir sera utile.

11

Utilisez ce code:

public class GestureHelper implements OnTouchListener {

private final GestureDetector mGestureDetector;

public GestureHelper(Context context) {
    mGestureDetector = new GestureDetector(context, new GestureListener(this));
}

public void onSwipeRight() {
};

public void onSwipeLeft() {
};

public void onSwipeTop() {
};

public void onSwipeBottom() {
};

public void onDoubleTap() {
};

public void onClick() {
};

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

private static final class GestureListener extends SimpleOnGestureListener {

    private static final int SWIPE_THRESHOLD = 100;
    private static final int SWIPE_VELOCITY_THRESHOLD = 100;
    private GestureHelper mHelper;

    public GestureListener(GestureHelper helper) {
        mHelper = helper;
    }

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        mHelper.onClick();
        return true;
    }

    @Override
    public boolean onDoubleTap(MotionEvent e) {
        mHelper.onDoubleTap();
        return true;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        boolean result = false;
        try {
            float diffY = e2.getY() - e1.getY();
            float diffX = e2.getX() - e1.getX();
            if (Math.abs(diffX) > Math.abs(diffY)) {
                if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffX > 0) {
                        mHelper.onSwipeRight();
                    } else {
                        mHelper.onSwipeLeft();
                    }
                }
            } else {
                if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffY > 0) {
                        mHelper.onSwipeBottom();
                    } else {
                        mHelper.onSwipeTop();
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return result;
    }
}

}

Étendre cette classe et utiliser comme ça ...

view.setOnTouchListener(new SomeYourGestureHelper(context, someParameters));
10
siarhei sin

Utilisez return false au lieu de return true

4
stannums

Il existe de nombreuses solutions à ce problème, la meilleure pour moi consiste à éliminer totalement setOnClickListener et à l'intérieur du onTouchListener, vérifiez si l'action est ACTION_UP, puis à l'intérieur de cette vérification, si le dernier précédent est ACTION_DOWN:

case MotionEvent.ACTION_UP:
    if (lastAction == MotionEvent.ACTION_DOWN) {
        //code for click   
        .
        .
        lastAction = event.getAction();
    }

lastAction est int et je le mets à jour à la fin de chaque action

1
Armstring