Обнаружить сенсорное нажатие против длительного нажатия против движения? - PullRequest
64 голосов
/ 01 декабря 2010

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

Я хотел бы иметь изображение (в виде круга) на моем экране, которое я могу перетаскивать.Затем, когда я нажимаю его один раз (короткое / обычное нажатие), появляется тост с некоторой базовой информацией об этом.Когда я долго нажимаю на него, появляется AlertDialog со списком, чтобы выбрать другое изображение (круг, прямоугольник или треугольник).

Я создал собственный View с моим OnTouchListener, чтобы обнаруживать события и рисовать изображение вOnDraw.OnTouchListener.onTouch работает примерно так:

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

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

Я немного "взломал" это, введя новую переменную "mTouchDelay", для которой я установил 0 в ACTION_DOWN, увеличил MOVE и, если это> = 3 в MOVEЯ выполняю свой код "переместить".Но у меня такое ощущение, что на самом деле это не тот путь.

Я так и не узнал, как обнаружить долгое нажатие.Виновником действительно является MOVE, который, кажется, всегда срабатывает.

Пример того, чего я грубо хочу, см. В приложении Android «DailyStrip»: оно показывает изображение комикса.Вы можете перетащить его, если он слишком большой для экрана.Вы можете нажать его один раз, чтобы открыть некоторые элементы управления, и долго нажимать его для выбора меню параметров.

PS.Я пытаюсь заставить его работать на Android 1.5, так как мой телефон работает только на 1.5.

Ответы [ 9 ]

92 голосов
/ 10 мая 2013

Этот код может различать щелчок и движение (перетаскивание, прокрутка).В onTouchEvent установите флаг isOnClick и начальные координаты X, Y на ACTION_DOWN.Снимите флажок ACTION_MOVE (имея в виду, что часто обнаруживается непреднамеренное движение, которое может быть решено с помощью 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;
}

Для LongPress, как предложено выше, GestureDetector - это путь.Проверьте это Q & A:

Обнаружение долгого нажатия с Android

20 голосов
/ 01 декабря 2010

Из документов Android -

onLongClick ()

Из View.OnLongClickListener.Это вызывается, когда пользователь либо касается и удерживает элемент (в сенсорном режиме), либо фокусируется на элементе с помощью навигационных клавиш или трекбола и нажимает и удерживает подходящую клавишу «ввод» или нажимает и удерживает трекболна одну секунду).

onTouch ()

Из View.OnTouchListener.Это вызывается, когда пользователь выполняет действие, квалифицируемое как событие касания, включая нажатие, отпускание или любой жест движения на экране (в пределах элемента).

Что касается "перемещения происходит"даже когда я касаюсь «Я бы установил дельту и удостоверился, что представление было перемещено, по крайней мере, дельтой, прежде чем нажать на код движения.Если это не так, снимите сенсорный код.

15 голосов
/ 15 февраля 2012

Я обнаружил это после долгих экспериментов.

В инициализации вашей деятельности:

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);
3 голосов
/ 10 апреля 2014

Если вам нужно различить щелчок, длинное нажатие и прокрутку, используйте GestureDetector

Осуществление деятельности GestureDetector.OnGestureListener

затем создайте детектор в onCreate, например

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

затем, при необходимости, установите OnOtouchListener в вашем представлении (например, веб-просмотре), где

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

и теперь вы можете использовать Override onScroll, onFling, showPress (обнаружить длительное нажатие) или onSingleTapUp (обнаружить щелчок)

3 голосов
/ 02 июля 2012

Я искал подобное решение, и это то, что я бы предложил. В методе OnTouch запишите время для события MotionEvent.ACTION_DOWN, а затем для MotionEvent.ACTION_UP снова запишите время. Таким образом, вы также можете установить свой собственный порог. После нескольких экспериментов вы узнаете максимальное время в миллисекундах, которое потребуется для записи простого касания, и вы можете использовать его в движении или другим способом, как вам нравится.

Надеюсь, это помогло. Прокомментируйте, если вы использовали другой метод и решили свою проблему.

2 голосов
/ 24 сентября 2012

Я думаю, вам следует реализовать GestureDetector.OnGestureListener, как описано в Использование GestureDetector для обнаружения длинных касаний, двойного касания, прокрутки или других событий касания в Android и androidsnippets и затем реализовать логику касанияв onSingleTapUp и переместить логику в события onScroll

0 голосов
/ 22 сентября 2016

GestureDetector.SimpleOnGestureListener имеет методы, помогающие в этих 3 случаях;

   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);
        }
    });
0 голосов
/ 07 января 2013

просто нужно событие касания в классе оверлея. проверьте это, мне помогло

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

0 голосов
/ 26 сентября 2012

Я только что имел дело с этим беспорядком после того, как хотел, чтобы longclick не заканчивался событием click.

Вот что я сделал.

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;

Это что-то вроде хака, но это работает.

...