Подтвердить что ты не робот

Обнаружение долгой печати с помощью Android

В настоящее время я использую

onTouchEvent(MotionEvent event){
}

чтобы обнаружить, когда пользователь нажимает мой glSurfaceView, есть способ обнаружить, когда сделан длинный клик. Я предполагаю, что если я не могу найти много в dev docs, то это будет какая-то работа вокруг метода. Что-то вроде регистрации ACTION_DOWN и просмотра того, как долго это происходит до ACTION_UP.

Как вы обнаруживаете длительные нажатия на андроид, используя opengl-es?

4b9b3361

Ответ 1

Попробуйте следующее:

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);
};

Ответ 2

GestureDetector - лучшее решение.

Вот интересная альтернатива. В onTouchEvent для каждого графика ACTION_DOWN используется Runnable для запуска через 1 секунду. На каждом ACTION_UP или ACTION_MOVE отмените запланированное Runnable. Если отключение ACTION_DOWN происходит менее 1 секунды, Runnable не будет работать.

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);
}

Ответ 3

У меня есть код, который обнаруживает щелчок, длинный клик и движение. Это довольно сложная комбинация ответов, приведенных выше, и изменений, внесенных мной в каждую страницу документации.

//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;
    }

Я подтверждаю, что он работает, поскольку я использовал его в своем приложении.

Ответ 4

Когда вы подразумеваете нажатия на пользователя, вы имеете в виду клик? Щелчок - это когда пользователь нажимает вниз, а затем сразу поднимает палец. Поэтому он охватывает два события onTouch. Вы должны сохранить использование onTouchEvent для вещей, которые происходят при первоначальном касании или после релиза.

Таким образом, вы должны использовать onClickListener, если это щелчок.

Ваш ответ аналогичен: используйте onLongClickListener.

Ответ 5

Я создал фрагмент - вдохновленный фактическим источником просмотра - который надежно обнаруживает длинные клики/нажатия с пользовательской задержкой. Но это в Котлине:

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
}

Ответ 6

Решение MSquare работает только в том случае, если вы держите определенный пиксель, но это необоснованное ожидание для конечного пользователя, если они не используют мышь (которой они не пользуются, они используют пальцы).

Итак, я добавил немного порога для расстояния между DOWN и UP, в случае, если между ними было действие MOVE.

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);
}

Ответ 7

Идея заключается в создании Runnable для выполнения длинного щелчка в будущем, но это выполнение может быть отменено из-за щелчка или перемещения.

Вы также должны знать, когда длительный щелчок был потреблен, и когда он отменяется, потому что пальцы слишком сильно перемещаются. Мы используем initialTouchX & initialTouchY для проверки того, выходит ли пользователь из квадратной области 10 пикселей, по 5 с каждой стороны.

Вот мой полный код для делегирования Click & LongClick из Cell в ListView для Activity с 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;
    }

ClickDelegate - это interface для отправки событий кликов в класс обработчика, например Activity

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

И все, что вам нужно, - это реализовать его в своей Activity или родительском View если вам нужно делегировать поведение:

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 a click
        }
    }
}

Ответ 8

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;
            }
        });

Ответ 9

Вот подход, основанный на прекрасной идее MSquare для обнаружения длительного нажатия кнопки, который имеет дополнительную функцию: операция не только выполняется в ответ на долгое нажатие, но операция повторяется до тех пор, пока не появится сообщение MotionEvent.ACTION_UP. получено. В этом случае действия длинного и короткого нажатия одинаковы, но они могут быть разными.

Обратите внимание, что, как сообщали другие, удаление обратного вызова в ответ на сообщение MotionEvent.ACTION_MOVE предотвратило выполнение обратного вызова, так как я не мог держать палец в руках. Я обошел эту проблему, проигнорировав это сообщение.

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");   
}

Ответ 10

Я нашел одно решение, и оно не требует определения работоспособных или других вещей, и оно работает нормально.

    var lastTouchTime: Long = 0

    // ( ViewConfiguration.#.DEFAULT_LONG_PRESS_TIMEOUT =500)
    val longPressTime = 500

    var lastTouchX = 0f
    var lastTouchY = 0f

    view.setOnTouchListener { v, event ->

        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                lastTouchTime = SystemClock.elapsedRealtime()
                lastTouchX = event.x
                lastTouchY = event.y
                [email protected] true
            }
            MotionEvent.ACTION_UP -> {
                if (SystemClock.elapsedRealtime() - lastTouchTime > longPressTime
                        && Math.abs(event.x - lastTouchX) < 3
                        && Math.abs(event.y - lastTouchY) < 3) {
                    Log.d(TAG, "Long press")
                }
                [email protected] true
            }
            else -> {
                [email protected] false
            }
        }

    }