Android: настраиваемый вид onClickEvent с местоположениями X и Y

У меня есть пользовательский вид, и я хочу получить координаты X и Y щелчка пользователя. Я обнаружил, что могу получить координаты только из onTouchEvent, а onClickEvent не сработает, если у меня есть onTouchEvent. К сожалению, onTouchEvent срабатывает, когда пользователь перетаскивает экран, а также щелкает.

Я пытался различать их, но все равно срабатывает код при перетаскивании:

 public boolean onTouchEvent(MotionEvent event) {
  int action = event.getAction();
  if (action == MotionEvent.ACTION_DOWN) {
                //fires on drag and click

Я просмотрел это, но, как я уже упоминал выше, я не думаю, решение будет работать, так как я не могу заставить события onClick и onTouch работать одновременно. Может быть, я делаю что-то неправильно в этом отношении, есть ли нормальный способ справиться с захватом пользовательского ввода в пользовательских событиях? Должен ли я одновременно использовать события onClick и onTouch?

Спасибо, Мартин


person Martyn    schedule 13.05.2010    source источник


Ответы (6)


Теперь я не знаю о коротком замыкании onTouchEvent onClick, и я не знаю, может быть, вам нужно установить android:clickable в true (или setClickable(true)). Но если вы не можете заставить его работать правильно, вы можете использовать логическое значение в onTouchEvent, чтобы имитировать обнаружение кликов, если ничего не помогает. в ACTION_DOWN установите для него значение true (isClicking или что-то в этом роде), в ACTION_MOVE установите для него значение false (поскольку пользователь перетаскивает, поэтому не щелкает), а затем в ACTION_UP вы можете проверить это. Если это правда, это означает, что пользователь нажал, но не перетащил. Это хакерство, но если вы не можете заставить onClick работать, это в основном одно и то же.

person Rich    schedule 13.05.2010
comment
К сожалению, проверка на отсутствие ACTION_MOVE не будет надежно работать — практически невозможно сделать щелчок рукой, не двигая при этом пальцем. (Это одна из тех вещей, о которых тестирование эмулятора не говорит вам...) Вам нужно будет проверить, что движение или временная задержка были очень маленькими. - person Steve Haley; 13.05.2010
comment
На самом деле ответ состоял в том, чтобы просто проверить действие MotionEvent.ACTION_UP. Видимо это только в случае нажатия, а не перетаскивания. - person Martyn; 13.05.2010
comment
@Martyn: Возможно, из-за вашей конкретной ситуации происходит что-то странное, но обычно ACTION_UP всегда вызывается, когда пользователь убирает палец с экрана. Предполагая, что этого не произойдет, перетаскивание может каким-то образом сломаться в будущем, например, при использовании другой версии Android или при изменении корневого типа представления, которое вы расширяете. (В частности, веб-представления ведут себя очень странно, будьте осторожны: P) - person Steve Haley; 13.05.2010

Что вы возвращаете в конце вашего onTouchEvent? Согласно документации, возврат true означает, что «событие было полностью обработано, с ним больше ничего не нужно делать», а возврат false означает, что система продолжит обработку. Я не проверял это с вашей конкретной ситуацией, но это говорит о том, что возврат false может сработать. Это заставило бы систему продолжить обработку касания/щелчка и отправить его в следующий вид «внизу».

Если это не сработает, то я пока не могу придумать лучшего решения, чем сделать что-то похожее на то, что предложил Рич. Вы можете сделать что-то вроде получения времени в ACTION_DOWN, а затем в ACTION_UP и сравнить прошедшее время. Если оно меньше 100 миллисекунд, то его следует интерпретировать как щелчок. Затем вы можете активировать любой код, который хотите поместить в свой прослушиватель кликов.

Например, вот как вы могли бы закодировать это:

long touchDownTime; // This has to be a class field so that it persists 
                    // between calls to onTouchEvent

public boolean onTouchEvent(MotioNEvent event){
    boolean handled = false;

    int action = event.getAction();
    switch (action){
    case MotionEvent.ACTION_DOWN:
        touchDownTime = SystemClock.elapsedRealtime();
        break;

    case MotionEvent.ACTION_UP:
        if (SystemClock.elapsedRealtime() - touchDownTime <= 100){
            int x = event.getX(); //or event.getRawX();
            int y = event.getY();
            performYourClick(x, y);
            handled = true;
        }
        break;
    }

    return handled;
}

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

person Steve Haley    schedule 13.05.2010
comment
Этот ответ был тем, что я искал. Более простой способ найти touchDownTime: long touchDownTime = event.getEventTime() - event.getDownTime(); Это не обязательно должно быть полем класса. - person Mario Kutlev; 12.03.2014

К вашему сведению, в моих тестах похоже, что onTouch переопределяет onClick для представления, независимо от того, возвращает ли onTouch значение true или false.

-Фринк

person FrinkTheBrave    schedule 17.08.2010

Я смог решить эту проблему

Я создал открытый класс Custom View QuestionBuilderView extends View

В файле макета

 < com.example.android.view.QuestionBuilderView

        android:id="@+id/questionbuilderview"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content" />

В основном действии попробуйте вызвать настраиваемое представление и установите прослушиватель событий Onclick/On Touch в представление.

 View questionBuilder =  findViewById(R.id.questionbuilderview);
         questionBuilder.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View view, MotionEvent event) {
                // TODO Auto-generated method stub
                float touched_x = event.getX();
               float  touched_y = event.getY();
               Toast.makeText(getApplicationContext(), " "+touched_x +","+touched_y, Toast.LENGTH_LONG).show();
              //  int action = event.getAction();


                return true;
            }
person Manjunath    schedule 18.12.2013

я думаю, вам нужно вызвать super.onTouchEvent(event), потому что в этом методе обнаруживается щелчок.

person user6089461    schedule 20.03.2016

Вы должны использовать GestureDetector. Подкласс GestureDetector.SimpleOnGestureListener и переопределение метода onDown(MotionEvent event) для возврата true. Затем переопределите onSingleTapConfirmed. Передайте прослушиватель конструктору GestureDetector. Затем вызовите setOnDoubleTapListener с этим слушателем в качестве параметра:

// in your view class constructor
GestureDetector.SimpleOnGestureListener listener = new GestureDetector.SimpleOnGestureListener() {
   @Override
   public boolean onDown(MotionEvent e) {
      return true;
   }
   @Override
   public boolean onSingleTapConfirmed(MotionEvent e) {
      // do whatever you want
      return true;
   }
};
mDetector = new GestureDetector(getContext(), listener);
mDetector.setOnDoubleTapListener(listener);

Затем вы можете передать MotionEvents детектору:

@Override
public boolean onTouchEvent(MotionEvent event) {
   return mDetector.onTouchEvent(event);
}
person user6089461    schedule 20.03.2016