it-swarm.com.de

Langes Drücken mit Android erkennen

Ich benutze gerade

onTouchEvent(MotionEvent event){
}

zu erkennen, wenn der Benutzer auf meine glSurfaceView-Taste drückt, gibt es eine Möglichkeit, zu erkennen, wann ein langer Klick erfolgt. Ich vermute, wenn ich nicht viel in den Entwicklerdokumenten finden kann, dann wird es eine Art Umgehungsmethode sein. Etwas wie das Registrieren von ACTION_DOWN und das Anzeigen der Zeitdauer vor ACTION_UP.

Wie erkennt man mit opengl-es lange Drücke auf Android?

62
Jack

Versuche dies:

final GestureDetector gestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
    public void onLongPress(MotionEvent e) {
        Log.e("", "Longpress detected");
    }
});

public boolean onTouchEvent(MotionEvent event) {
    return gestureDetector.onTouchEvent(event);
};
98
Daniel Fekete

GestureDetector ist die beste Lösung. 

Hier ist eine interessante Alternative. In onTouchEvent Bei jedem ACTION_DOWN Schedule ein Run, das in 1 Sekunde ausgeführt werden kann. Bei jedem ACTION_UP oder ACTION_MOVE stornieren Sie das geplante Runable. Wenn der Abbruch weniger als 1s von ACTION_DOWN event erfolgt, wird Runnable nicht ausgeführt.

final Handler handler = new Handler(); 
Runnable mLongPressed = new Runnable() { 
    public void run() { 
        Log.i("", "Long press!");
    }   
};

@Override
public boolean onTouchEvent(MotionEvent event, MapView mapView){
    if(event.getAction() == MotionEvent.ACTION_DOWN)
        handler.postDelayed(mLongPressed, ViewConfiguration.getLongPressTimeout());
    if((event.getAction() == MotionEvent.ACTION_MOVE)||(event.getAction() == MotionEvent.ACTION_UP))
        handler.removeCallbacks(mLongPressed);
    return super.onTouchEvent(event, mapView);
}
142
MSquare

Ich habe einen Code, der einen Klick, einen langen Klick und eine Bewegung erkennt. Es ist eine Kombination aus der oben gegebenen Antwort und den Änderungen, die ich durch das Aufrufen der Dokumentationsseite vorgenommen habe. 

//Declare this flag globally
boolean goneFlag = false;

//Put this into the class
final Handler handler = new Handler(); 
    Runnable mLongPressed = new Runnable() { 
        public void run() { 
            goneFlag = true;
            //Code for long click
        }   
    };

//onTouch code
@Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {    
        case MotionEvent.ACTION_DOWN:
            handler.postDelayed(mLongPressed, 1000);
            //This is where my code for movement is initialized to get original location.
            break;
        case MotionEvent.ACTION_UP:
            handler.removeCallbacks(mLongPressed);
            if(Math.abs(event.getRawX() - initialTouchX) <= 2 && !goneFlag) {
                //Code for single click
                return false;
            }
            break;
        case MotionEvent.ACTION_MOVE:
            handler.removeCallbacks(mLongPressed);
            //Code for movement here. This may include using a window manager to update the view
            break;
        }
        return true;
    }

Ich bestätige, dass es funktioniert, wie ich es in meiner eigenen Anwendung verwendet habe. 

5
SanVed

Wenn Sie auf Benutzer drücken, meinen Sie einen Klick? Ein Klicken ist, wenn der Benutzer den Finger herunterdrückt und dann sofort den Finger anhebt. Daher umfasst es zwei onTouch-Ereignisse. Sie sollten die Verwendung von onTouchEvent für Dinge speichern, die bei der ersten Berührung oder nach der Veröffentlichung passieren.

Daher sollten Sie onClickListener verwenden, wenn es sich um einen Klick handelt.

Ihre Antwort ist analog: Verwenden Sie onLongClickListener.

3
Ian

Die Lösung von MSquare funktioniert nur, wenn Sie ein bestimmtes Pixel besitzen. Dies ist jedoch für einen Endbenutzer eine unzumutbare Erwartung, es sei denn, er verwendet eine Maus (was nicht der Fall ist, Finger benutzen).

Also fügte ich ein bisschen einen Schwellenwert für die Entfernung zwischen der DOWN- und der UP-Aktion hinzu, falls dazwischen eine MOVE-Aktion war.

final Handler longPressHandler = new Handler();
Runnable longPressedRunnable = new Runnable() {
    public void run() {
        Log.e(TAG, "Long press detected in long press Handler!");
        isLongPressHandlerActivated = true;
    }
};

private boolean isLongPressHandlerActivated = false;

private boolean isActionMoveEventStored = false;
private float lastActionMoveEventBeforeUpX;
private float lastActionMoveEventBeforeUpY;

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    if(event.getAction() == MotionEvent.ACTION_DOWN) {
        longPressHandler.postDelayed(longPressedRunnable, 1000);
    }
    if(event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_HOVER_MOVE) {
        if(!isActionMoveEventStored) {
            isActionMoveEventStored = true;
            lastActionMoveEventBeforeUpX = event.getX();
            lastActionMoveEventBeforeUpY = event.getY();
        } else {
            float currentX = event.getX();
            float currentY = event.getY();
            float firstX = lastActionMoveEventBeforeUpX;
            float firstY = lastActionMoveEventBeforeUpY;
            double distance = Math.sqrt(
                    (currentY - firstY) * (currentY - firstY) + ((currentX - firstX) * (currentX - firstX)));
            if(distance > 20) {
                longPressHandler.removeCallbacks(longPressedRunnable);
            }
        }
    }
    if(event.getAction() == MotionEvent.ACTION_UP) {
        isActionMoveEventStored = false;
        longPressHandler.removeCallbacks(longPressedRunnable);
        if(isLongPressHandlerActivated) {
            Log.d(TAG, "Long Press detected; halting propagation of motion event");
            isLongPressHandlerActivated = false;
            return false;
        }
    }
    return super.dispatchTouchEvent(event);
}
1
EpicPandaForce

Ich habe ein snippet - erstellt, das von der tatsächlichen Quelle für das Anzeigen inspiriert wurde - das lange Klicks/Druckvorgänge mit einer benutzerdefinierten Verzögerung zuverlässig erkennt. Aber es ist in Kotlin:

val LONG_PRESS_DELAY = 500

val handler = Handler()
var boundaries: Rect? = null

var onTap = Runnable {
    handler.postDelayed(onLongPress, LONG_PRESS_DELAY - ViewConfiguration.getTapTimeout().toLong())
}

var onLongPress = Runnable {

    // Long Press
}

override fun onTouch(view: View, event: MotionEvent): Boolean {
    when (event.action) {
        MotionEvent.ACTION_DOWN -> {
            boundaries = Rect(view.left, view.top, view.right, view.bottom)
            handler.postDelayed(onTap, ViewConfiguration.getTapTimeout().toLong())
        }
        MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
            handler.removeCallbacks(onLongPress)
            handler.removeCallbacks(onTap)
        }
        MotionEvent.ACTION_MOVE -> {
            if (!boundaries!!.contains(view.left + event.x.toInt(), view.top + event.y.toInt())) {
                handler.removeCallbacks(onLongPress)
                handler.removeCallbacks(onTap)
            }
        }
    }
    return true
}
1
Benjoyo

Die Idee ist die Erstellung einer Runnable zum Ausführen eines langen Klicks in einer Zukunft. Diese Ausführung kann jedoch aufgrund eines Klicks oder Verschiebens abgebrochen werden.

Sie müssen auch wissen, wann ein langer Klick verbraucht wurde und wann der Vorgang abgebrochen wird, weil der Finger zu viel bewegt wurde. Wir verwenden initialTouchX & initialTouchY, um zu prüfen, ob der Benutzer einen quadratischen Bereich von 10 Pixeln (5 Seiten) verlässt.

Hier ist mein vollständiger Code zum Delegieren von Click & LongClick von Cell in ListView an Activity mit OnTouchListener:

    ClickDelegate delegate; 
    boolean goneFlag = false;
    float initialTouchX;
    float initialTouchY;
    final Handler handler = new Handler();
    Runnable mLongPressed = new Runnable() {
        public void run() {
            Log.i("TOUCH_EVENT", "Long press!");
            if (delegate != null) {
                goneFlag = delegate.onItemLongClick(index);
            } else {
                goneFlag = true;
            }
        }
    };

    @OnTouch({R.id.layout})
    public boolean onTouch (View view, MotionEvent motionEvent) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_DOWN:
                handler.postDelayed(mLongPressed, ViewConfiguration.getLongPressTimeout());
                initialTouchX = motionEvent.getRawX();
                initialTouchY = motionEvent.getRawY();
                return true;
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_CANCEL:
                if (Math.abs(motionEvent.getRawX() - initialTouchX) > 5 || Math.abs(motionEvent.getRawY() - initialTouchY) > 5) {
                    handler.removeCallbacks(mLongPressed);
                    return true;
                }
                return false;
            case MotionEvent.ACTION_UP:
                handler.removeCallbacks(mLongPressed);
                if (goneFlag || Math.abs(motionEvent.getRawX() - initialTouchX) > 5 || Math.abs(motionEvent.getRawY() - initialTouchY) > 5) {
                    goneFlag = false;
                    return true;
                }
                break;
        }
        Log.i("TOUCH_EVENT", "Short press!");
        if (delegate != null) {
            if (delegate.onItemClick(index)) {
                return false;
            }
        }
        return false;
    }

ClickDelegateist eine interface zum Senden von Klickereignissen an die Handler-Klasse wie eine Activity

    public interface ClickDelegate {
        boolean onItemClick(int position);
        boolean onItemLongClick(int position);
    }

Alles, was Sie brauchen, ist, es in Ihre Activity oder übergeordnete View zu implementieren, wenn Sie das Verhalten delegieren müssen:

public class MyActivity extends Activity implements ClickDelegate {

    //code...
    //in some place of you code like onCreate, 
    //you need to set the delegate like this:
    SomeArrayAdapter.delegate = this;
    //or:
    SomeViewHolder.delegate = this;
    //or:
    SomeCustomView.delegate = this;

    @Override
    public boolean onItemClick(int position) {
        Object obj = list.get(position);
        if (obj) {
            return true; //if you handle click
        } else {
            return false; //if not, it could be another event
        }
    }

    @Override
    public boolean onItemLongClick(int position) {
        Object obj = list.get(position);
        if (obj) {
            return true; //if you handle long click
        } else {
            return false; //if not, it's a click
        }
    }
}
1
IgniteCoders
setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {

                int action = MotionEventCompat.getActionMasked(event);


                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        longClick = false;
                        x1 = event.getX();
                        break;

                    case MotionEvent.ACTION_MOVE:
                        if (event.getEventTime() - event.getDownTime() > 500 && Math.abs(event.getX() - x1) < MIN_DISTANCE) {
                            longClick = true;
                        }
                        break;

                    case MotionEvent.ACTION_UP:
                                if (longClick) {
                                    Toast.makeText(activity, "Long preess", Toast.LENGTH_SHORT).show();
                                } 
                }
                return true;
            }
        });
0
LesterSenk4454

Hier ein Ansatz, der auf der Nice-Idee von MSquare zum Erkennen eines langen Tastendrucks basiert und eine zusätzliche Funktion aufweist: Es wird nicht nur ein Vorgang als Reaktion auf einen langen Tastendruck ausgeführt, sondern der Vorgang wird wiederholt, bis eine MotionEvent.ACTION_UP-Nachricht angezeigt wird empfangen. In diesem Fall sind die Aktionen für lange Betätigung und für kurze Betätigung gleich, aber sie können sich unterscheiden. 

Beachten Sie, dass, wie andere berichtet haben, das Entfernen des Rückrufs als Antwort auf eine MotionEvent.ACTION_MOVE-Nachricht verhindert hat, dass der Rückruf jemals ausgeführt wird, da ich meinen Finger nicht genug halten konnte. Ich bin dieses Problem umgangen, indem ich diese Nachricht ignoriert habe. 

private void setIncrementButton() {
    final Button btn = (Button) findViewById(R.id.btn);
    final Runnable repeater = new Runnable() {
        @Override
        public void run() {
            increment();
            final int milliseconds = 100;
            btn.postDelayed(this, milliseconds);
        }
    };
    btn.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent e) {
            if (e.getAction() == MotionEvent.ACTION_DOWN) {
                increment();
                v.postDelayed(repeater, ViewConfiguration.getLongPressTimeout());
            } else if (e.getAction() == MotionEvent.ACTION_UP) {
                v.removeCallbacks(repeater);
            }
            return true;
        }
    });
}

private void increment() {
    Log.v("Long Press Example", "TODO: implement increment operation");   
}
0
stevehs17