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

Обнаружить сенсорное нажатие против длинного нажатия против движения?

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

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

Я сделал собственный вид с собственным 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". Но у меня такое чувство, что на самом деле это не так.

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

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

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

4b9b3361

Ответ 1

Этот код может различать щелчок и движение (перетаскивание, прокрутка). В 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

Ответ 2

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

onLongClick()

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

onTouch()

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

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

Активность реализует GestureDetector.OnGestureListener

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

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

то необязательно setOnTouchListener в вашем представлении (например, webview), где

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

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

Ответ 7

Я просто справлялся с этим беспорядком после того, как longcick не закончил событие 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;

Это немного взломать, но он работает.

Ответ 9

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

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