web-dev-qa-db-fra.com

singletap touch detect dans la méthode Ontouch de la vue

J'avais besoin d'une détection tactile singletap dans la méthode ontouch de ma vue personnalisée. J'ai essayé d'obtenir les valeurs x et y à la fois dans ACTION-DOWN et ACTION-UP et dans ACTION-UP, j'ai posé comme condition que si a les valeurs de X et Y dans ACTIONDOWN et ACTION-UP sont égales, il faut les prendre comme une simple tape. .

Mon code est comme suit

@Override
public boolean onTouchEvent(MotionEvent ev) {
   if (!mSupportsZoom && !mSupportsPan) return false;

    mScaleDetector.onTouchEvent(ev);

    final int action = ev.getAction();
    switch (action & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN: {
        final float x = ev.getX();
        final float y = ev.getY();

        mLastTouchX = x;  //here i get x and y values in action down
        mLastTouchY = y;
        mActivePointerId = ev.getPointerId(0);

        break;
    }

    case MotionEvent.ACTION_MOVE: {
        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
        final float x = ev.getX(pointerIndex);
        final float y = ev.getY(pointerIndex);

        if (mSupportsPan && !mScaleDetector.isInProgress()) {
            final float dx = x - mLastTouchX;
            final float dy = y - mLastTouchY;

            mPosX += dx;
            mPosY += dy;
            //mFocusX = mPosX;
            //mFocusY = mPosY;

            invalidate();
        }

        mLastTouchX = x;
        mLastTouchY = y;

        break;
    }

    case MotionEvent.ACTION_UP: {

        final float x = ev.getX();
        final float y = ev.getY();

        touchupX=x;   //here is get x and y values at action up
        touchupY=y; 

        if(mLastTouchX == touchupX && mLastTouchY == touchupY){  //my condition if both the x and y values are same .

            PinchZoomPanActivity2.tapped1(this.getContext(), 100); //my method if the singletap is detected

        }
        else{

        }

        mActivePointerId = INVALID_POINTER_ID;

        break;
    }

    case MotionEvent.ACTION_CANCEL: {
        mActivePointerId = INVALID_POINTER_ID;
        break;
    }

    case MotionEvent.ACTION_POINTER_UP: {
        final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 
                >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
        final int pointerId = ev.getPointerId(pointerIndex);
        if (pointerId == mActivePointerId) {

            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
            mLastTouchX = ev.getX(newPointerIndex);
            mLastTouchY = ev.getY(newPointerIndex);
            mActivePointerId = ev.getPointerId(newPointerIndex);
        }
        break;
    }
    }

    return true;
}

mais je ne peux pas le faire. Je veux dire à chaque action jusqu'à ma méthode s'appelle. même lorsque les valeurs x et y de actionup et d’actiondown ne sont pas identiques. et je pense que j'ai également besoin de mettre un peu de portée à la singletap lorsque nous touchons avec notre doigt sur l'écran. Quelqu'un peut-il me suggérer des moyens?

16
Sandeep R

J'ai également rencontré le même problème récemment et fini par devoir mettre en place un système anti-rebond pour le faire fonctionner. Ce n'est pas idéal, mais c'est assez fiable jusqu'à ce que je puisse trouver quelque chose de mieux.

View.onClickListener était beaucoup plus fiable pour moi, mais malheureusement, j'ai besoin de MotionEvent de OnTouchListener.

Edit: Suppression de l'excès de code qui provoquerait son échec ici

class CustomView extends View {

    private static long mDeBounce = 0;

    static OnTouchListener listenerMotionEvent = new OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            if ( Math.abs(mDeBounce - motionEvent.getEventTime()) < 250) {
                //Ignore if it's been less then 250ms since
                //the item was last clicked
                return true;
            }

            int intCurrentY = Math.round(motionEvent.getY());
            int intCurrentX = Math.round(motionEvent.getX());
            int intStartY = motionEvent.getHistorySize() > 0 ? Math.round(motionEvent.getHistoricalY(0)) : intCurrentY;
            int intStartX = motionEvent.getHistorySize() > 0 ? Math.round(motionEvent.getHistoricalX(0)) : intCurrentX;

            if ( (motionEvent.getAction() == MotionEvent.ACTION_UP) && (Math.abs(intCurrentX - intStartX) < 3) && (Math.abs(intCurrentY - intStartY) < 3) ) {
                if ( mDeBounce > motionEvent.getDownTime() ) {
                    //Still got occasional duplicates without this
                    return true;
                }

                //Handle the click

                mDeBounce = motionEvent.getEventTime();
                return true;
            }
            return false;
        }
    };
}
7
Jon

Pour détecter les appels simples et doubles sous Android, j'utilise les méthodes suivantes: 

class GestureTap extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onDoubleTap(MotionEvent e) {
        Log.i("onDoubleTap :", "" + e.getAction());
        return true;
   }

    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
        Log.i("onSingleTap :", "" + e.getAction());
        return true;
    }
}

Utilisez-le dans le constructeur de GestureDetector:

detector = new GestureDetector(this, new GestureTap());

Et ajoutez le code suivant dans l'auditeur onTouch 

@Override
public boolean onTouchEvent(MotionEvent event) {

    detector.onTouchEvent(event);

    return true;
}
36
Dhiral Pandya

Ajouter la réponse par souci d’intégralité et si quelqu'un d'autre parvient ici:

Vous pouvez utiliser une GestureDetector avec une OnTouchListener

final GestureDetector gestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
         //do something
            return true;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            super.onLongPress(e);
        }

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

 viewToTouch.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {

            return gestureDetector.onTouchEvent(event);
        }
    });
11
Droidekas

Ajoutez GestureDetector.SimpleOnGestureListener pour la méthode de visualisation et d'utilisation onSingleTapConfirmed in this.

Cette méthode est invoquée uniquement lorsque le système d'exploitation Android a confirmé que le contact est simple et pas double tap .

Vous pouvez google pour des exemples Android.

4
Charan

Il existe un moyen beaucoup plus simple et direct. Utilisez MotionEvent.ACTION_DOWN && MotionEvent.ACTION_UP pour chronométrer la différence entre les événements.

Le code complet peut être trouvé ici. https://stackoverflow.com/a/15799372/3659481

setOnTouchListener(new OnTouchListener() {
private static final int MAX_CLICK_DURATION = 200;
private long startClickTime;

@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            startClickTime = Calendar.getInstance().getTimeInMillis();
            break;
        }
        case MotionEvent.ACTION_UP: {
            long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;
            if(clickDuration < MAX_CLICK_DURATION) {
                //click event has occurred
            }
        }
    }
    return true;
}

}

4
marcomarandiz

Pensez que vous n’avez pas besoin d’utiliser un opérateur «égal». Au lieu de cela, utilisez approximativement la valeur 

case MotionEvent.ACTION_DOWN: {
    final int CONST = 5;
    final float x = ev.getX();
    final float y = ev.getY();

    mLastTouchXMax = x+CONST;  //here i get x and y values in action down
    mLastTouchXMin = x-CONST;
    mLastTouchYMax = y+CONST;
    mLastTouchYMin = y-CONST;
    mActivePointerId = ev.getPointerId(0);

    break;
}

Et dans ACTION_UP, vérifiez les valeurs X et Y entre les intervalles. 

0
Sergey Brazhnik
float dX,dY,x,y;     
tv.setOnTouchListener(new View.OnTouchListener() {
                                @Override
                                public boolean onTouch(View view, MotionEvent event) {
                                    switch (event.getAction()) {
                                        case MotionEvent.ACTION_UP:     //Event for On Click
                                            if(x==view.getX() && y==view.getY()){
                                                Toast.makeText(getApplicationContext(),"TextView Clicked",Toast.LENGTH_LONG).show();
                                            }
                                            break;
                                        case MotionEvent.ACTION_DOWN:
                                            x=view.getX();
                                            y=view.getY();
                                            dX = view.getX() - event.getRawX();
                                            dY = view.getY() - event.getRawY();
                                            break;

                                        case MotionEvent.ACTION_MOVE:
                                            view.animate()
                                                    .x(event.getRawX() + dX)
                                                    .y(event.getRawY() + dY)
                                                    .setDuration(0)
                                                    .start();
                                            break;
                                        default:
                                            return false;
                                    }
                                    return true;
                                }
                            });
0
Mohammad Bilal