Aanraken versus lang indrukken versus beweging detecteren?

Ik ben momenteel aan het spelen met Android-programmering, maar ik heb een klein probleem met het detecteren van verschillende aanraakgebeurtenissen, namelijk een normale druk op aanraking (druk op het scherm en laat meteen los), lang drukken (raak het scherm aan en houd de vinger erop) en beweging (slepen op het scherm).

Wat ik wilde doen, is een afbeelding (van een cirkel) op mijn scherm hebben die ik kan slepen. Als ik er dan één keer op druk (korte / normale druk), komt een Toast met wat basisinformatie erover. Als ik er lang op druk, verschijnt er een AlertDialog met een lijst om een ​​andere afbeelding te selecteren (cirkel, rechthoek of driehoek).

Ik heb een aangepaste weergave gemaakt met mijn eigen OnTouchListener om de gebeurtenissen te detecteren en de afbeelding in onDraw te tekenen. De OnTouchListener.onTouch gaat ongeveer als volgt:

// has a touch press started?
private boolean touchStarted = false;
// co-ordinates of image
private int x, y;
public boolean onTouch(View v, MotionEvent event) {
    int action = event.getAction();
    if (action == MotionEvent.ACTION_DOWN) {
        touchStarted = true;
    }
    else if (action == MotionEvent.ACTION_MOVE) {
        // movement: cancel the touch press
        touchStarted = false;
        x = event.getX();
        y = event.getY();
        invalidate(); // request draw
    }
    else if (action == MotionEvent.ACTION_UP) {
        if (touchStarted) {
            // touch press complete, show toast
            Toast.makeText(v.getContext(), "Coords: " + x + ", " + y, 1000).show();
        }
    }
    return true;
}

Het probleem is dat de pers niet helemaal werkt zoals verwacht, omdat wanneer ik het scherm nonchalant aanraak, hij ook een klein beetje beweging detecteert en de aanraakpers annuleert en in plaats daarvan over het beeld beweegt.

Ik heb hier een beetje omheen “gehackt” door een nieuwe variabele “mTouchDelay” te introduceren die ik op 0 heb gezet op ACTION_DOWN, verhoog in MOVE en als het >= 3 is in MOVE, voer ik mijn “move”-code uit. Maar ik heb het gevoel dat dit niet echt de juiste weg is.

Ik heb ook niet ontdekt hoe ik lang indrukken kan detecteren. De boosdoener is echt de MOVE die altijd lijkt te triggeren.

Voor een voorbeeld van wat ik ongeveer wil, zie de Android-applicatie “DailyStrip”: deze toont een afbeelding van een stripverhaal. Je kunt het slepen als het te groot is voor het scherm. Je kunt er één keer op tikken om sommige bedieningselementen te laten verschijnen en lang indrukken voor een optiemenu.

PS. Ik probeer het werkend te krijgen op Android 1.5, aangezien mijn telefoon alleen op 1.5 draait.


Antwoord 1, autoriteit 100%

Deze code kan onderscheid maken tussen klikken en bewegen (slepen, scrollen). Stel in onTouchEvent een vlag in isOnClick en de initiële X-, Y-coördinaten op ACTION_DOWN. Wis de vlag op ACTION_MOVE (let erop dat onbedoelde bewegingen vaak worden gedetecteerd, wat kan worden opgelost met een THRESHOLD-const).

private float mDownX;
private float mDownY;
private final float SCROLL_THRESHOLD = 10;
private boolean isOnClick;
@Override
public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            mDownX = ev.getX();
            mDownY = ev.getY();
            isOnClick = true;
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            if (isOnClick) {
                Log.i(LOG_TAG, "onClick ");
                //TODO onClick code
            }
            break;
        case MotionEvent.ACTION_MOVE:
            if (isOnClick && (Math.abs(mDownX - ev.getX()) > SCROLL_THRESHOLD || Math.abs(mDownY - ev.getY()) > SCROLL_THRESHOLD)) {
                Log.i(LOG_TAG, "movement detected");
                isOnClick = false;
            }
            break;
        default:
            break;
    }
    return true;
}

Voor LongPress, zoals hierboven gesuggereerd, is GestureDetector de juiste keuze. Check deze Q&A:

Lang indrukken detecteren met Android


Antwoord 2, autoriteit 23%

Vanuit de Android-documenten –

onLongClick()

Van View.OnLongClickListener. Dit wordt genoemd wanneer de gebruiker het item aanraakt en vasthoudt (in de aanraakmodus), of zich op het item concentreert met de navigatietoetsen of trackball en de geschikte “enter”-toets ingedrukt houdt of de trackball ingedrukt houdt ( één seconde).

onTouch()

Van View.OnTouchListener. Dit wordt genoemd wanneer de gebruiker een actie uitvoert die wordt gekwalificeerd als een aanraakgebeurtenis, inclusief een druk op, een release of een bewegingsgebaar op het scherm (binnen de grenzen van het item).

Wat betreft het “bewegen gebeurt zelfs als ik aanraak” zou ik een delta instellen en ervoor zorgen dat de View tenminste met de delta is verplaatst voordat ik de bewegingscode invoer. Als dat niet het geval is, start dan de aanraakcode.


Antwoord 3, autoriteit 16%

Ik ontdekte dit na veel experimenteren.

Bij de initialisatie van uw activiteit:

setOnLongClickListener(new View.OnLongClickListener() {
  public boolean onLongClick(View view) {
    activity.openContextMenu(view);  
    return true;  // avoid extra click events
  }
});
setOnTouch(new View.OnTouchListener(){
  public boolean onTouch(View v, MotionEvent e){
    switch(e.getAction & MotionEvent.ACTION_MASK){
      // do drag/gesture processing. 
    }
    // you MUST return false for ACTION_DOWN and ACTION_UP, for long click to work
    // you can return true for ACTION_MOVEs that you consume. 
    // DOWN/UP are needed by the long click timer.
    // if you want, you can consume the UP if you have made a drag - so that after 
    // a long drag, no long-click is generated.
    return false;
  }
});
setLongClickable(true);

Antwoord 4, autoriteit 3%

Ik was op zoek naar een vergelijkbare oplossing en dit is wat ik zou voorstellen.
In de OnTouch-methode noteert u de tijd voor de gebeurtenis MotionEvent.ACTION_DOWN en vervolgens voor MotionEvent.ACTION_UP de tijd opnieuw. Op deze manier kunt u ook uw eigen drempel instellen. Na een paar keer experimenteren weet je de maximale tijd in milli’s die nodig is om een ​​simpele aanraking op te nemen en je kunt dit in beweging of een andere methode gebruiken zoals je wilt.

Ik hoop dat dit heeft geholpen. Geef een reactie als je een andere methode hebt gebruikt en je probleem hebt opgelost.


Antwoord 5, autoriteit 3%

Als u onderscheid moet maken tussen klikken, lang indrukken en scrollen, gebruikt u GestureDetector

Activiteit implementeert GestureDetector.OnGestureListener

maak vervolgens een detector in onCreate bijvoorbeeld

mDetector = new GestureDetectorCompat(getActivity().getApplicationContext(),this);

stel vervolgens optioneelOnTouchListener in op uw View (bijvoorbeeld webview) waar

onTouch(View v, MotionEvent event) {
return mDetector.onTouchEvent(event);
}

en nu kunt u Override onScroll, onFling, showPress (lang indrukken detecteren) of onSingleTapUp (een klik detecteren) gebruiken


Antwoord 6, autoriteit 2%

Ik denk dat je GestureDetector.OnGestureListener moet implementeren
zoals beschreven in GestureDetector gebruiken om lang aanraken, dubbel tikken, scrollen of andere aanraakgebeurtenissen in Android te detecteren
en
androidsnippets
en vervolgens tiklogica implementeren in onSingleTapUp en logica verplaatsen in onScroll-gebeurtenissen


Antwoord 7

Ik was net bezig met deze puinhoop nadat ik wilde dat longclick niet eindigde met een klikgebeurtenis.

Dit is wat ik deed.

public boolean onLongClick(View arg0) {
    Toast.makeText(getContext(), "long click", Toast.LENGTH_SHORT).show();
    longClicked = true;
    return false;
}
public void onClick(View arg0) {
    if(!longClicked){
        Toast.makeText(getContext(), "click", Toast.LENGTH_SHORT).show();
    }
    longClick = false; // sets the clickability enabled
}
boolean longClicked = false;

Het is een beetje een hack, maar het werkt.


Antwoord 8

het had alleen een ontouch-gebeurtenis nodig in de overlay-klasse. controleer dit, het heeft me geholpen

http://mirnauman.wordpress.com/2012/04/16/android-google-maps-tutorial-part-6-getting-the-location-that-is-touched/


Antwoord 9

GestureDetector.SimpleOnGestureListener heeft methoden om in deze 3 gevallen te helpen;

  GestureDetector gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
        //for single click event.
        @Override
        public boolean onSingleTapUp(MotionEvent motionEvent) {
            return true;
        }
        //for detecting a press event. Code for drag can be added here.
        @Override
        public void onShowPress(MotionEvent e) {
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
            ClipData clipData = ClipData.newPlainText("..", "...");
            clipboardManager.setPrimaryClip(clipData);
            ConceptDragShadowBuilder dragShadowBuilder = new CustomDragShadowBuilder(child);
            // drag child view.
            child.startDrag(clipData, dragShadowBuilder, child, 0);
        }
        //for detecting longpress event
        @Override
        public void onLongPress(MotionEvent e) {
            super.onLongPress(e);
        }
    });

Other episodes