OnClickListener - x, y место события?


85

У меня есть собственный вид, полученный из View. Я хотел бы получать уведомления о щелчке по представлению и о координатах x, y, где произошел щелчок. То же и для длинных кликов.

Похоже, для этого мне нужно переопределить onTouchEvent(). Однако нет ли способа получить координаты события x, y из a OnClickListener?

Если нет, то как лучше всего определить, является ли событие движения «настоящим» щелчком по сравнению с длительным щелчком и т. Д.? onTouchEventГенерирует множество событий в быстрой последовательности и т.д.

Ответы:


92

Спасибо. Это было именно то, что я искал. Мой код сейчас:

imageView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN){
                textView.setText("Touch coordinates : " +
                        String.valueOf(event.getX()) + "x" + String.valueOf(event.getY()));
            }
            return true;
        }
    });

что делает именно то, о чем просил Марк ...


4
Эти координаты являются локальными по отношению к виду?
Найджел

7
Разве обработчик onTouch не должен возвращаться, falseчтобы не блокировать события касания? (View.OnTouchListener.onTouch возвращает true, если слушатель обработал событие, иначе false.)
ehartwell

5
Ну, не «точно», так OnClickListenerкак срабатывает, когда палец отпущен, ACTION_UPно с ограничениями: если был выполнен жест перемещения (смахивания), то OnClickListenerон не запускается, но ACTION_UPвсе равно будет обрабатываться.
Alex Semeniuk

Я пытаюсь написать текст по нажатым координатам. Я пробовал писать текст в координатах, (event.getX(), event.getY()) но он пишет не в правильном месте.
Prince

Вот мой вопрос: stackoverflow.com/questions/40199539/…
Prince

26

Полный пример

В других ответах отсутствуют некоторые детали. Вот полный пример.

public class MainActivity extends AppCompatActivity {

    // class member variable to save the X,Y coordinates
    private float[] lastTouchDownXY = new float[2];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // add both a touch listener and a click listener
        View myView = findViewById(R.id.my_view);
        myView.setOnTouchListener(touchListener);
        myView.setOnClickListener(clickListener);
    }

    // the purpose of the touch listener is just to store the touch X,Y coordinates
    View.OnTouchListener touchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {

            // save the X,Y coordinates
            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
                lastTouchDownXY[0] = event.getX();
                lastTouchDownXY[1] = event.getY();
            }

            // let the touch event pass on to whoever needs it
            return false;
        }
    };

    View.OnClickListener clickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // retrieve the stored coordinates
            float x = lastTouchDownXY[0];
            float y = lastTouchDownXY[1];

            // use the coordinates for whatever
            Log.i("TAG", "onLongClick: x = " + x + ", y = " + y);
        }
    };
}

Резюме

  • Добавьте переменную класса для хранения координат
  • Сохраните координаты X, Y, используя OnTouchListener
  • Доступ к координатам X, Y в OnClickListener

1
Вместо массива с плавающей запятой из 2 пробелов можно использовать Point ().
ZooMagic

Точка имеет X и Y целочисленного типа. Координаты являются значениями с плавающей запятой. Если я использую класс Point, я думаю, что потеряю точность ... Я новичок в Android и, возможно, я что-то пропустил.
mboada

@mboada, ты прав. PointF было бы лучше.
Suragch

Должен быть способ избежать onTouchListener и использовать только onClickListener. Почему-то ContextMenu в этом не нуждается. После щелчка по элементу и отображения меню с представлением в качестве привязки он знает, куда его поместить, рядом с местом касания. Смотрите здесь: stackoverflow.com/q/57290574/878126 . Вы знаете, как это возможно? Если да, то ответьте там.
разработчик Android

3

Переопределить onTouchEvent (MotionEvent ev)

Тогда вы сможете:

ev.getXLocation()

Или что-то вроде того. Есть бутерброды.


2
Привет, Том, да, мы можем использовать onTouchEvent, но тогда нам нужно самим различать щелчки и длинные щелчки, не так ли? Не имеет смысла, что они не предоставят вам способ узнать, где был щелчок или долгий щелчок в OnClickListener и т. Д.? Спасибо
Марк

21
Все, что вам нужно сделать, это записать положение x и y последнего события ACTION_UP или ACTION_MOVE и использовать эти значения в своем OnClickListener.
Romain Guy

@RomainGuy Но вы также должны рассчитать расстояние между двумя точками, чтобы определить щелчок. Если вы получаете событие ACTION_DOWN в (0,0), а затем событие ACTION_UP в (100,100), это определенно не щелчок.
TheRealChx101

@ chx101, то, что RomainGuy имел в виду (я думаю), было то, что если вы просто на touchevent записываете последние координаты action_up, то это координаты, которые вы можете использовать в onclick. однако я думаю, что на практике потребуется подклассификация представления, иначе onclick не будет вызван. вы также можете обнаружить касание как детектор жестов, как в stackoverflow.com/questions/19538747/… ответ
Ласси Киннунен

0

Вы можете создать функцию расширения в Kotlin, например:

fun View.setOnClickListenerWithPoint(action: (Point) -> Unit) {
    val coordinates = Point()
    val screenPosition = IntArray(2)
    setOnTouchListener { v, event ->
        if (event.action == MotionEvent.ACTION_DOWN) {
            v.getLocationOnScreen(screenPosition)
            coordinates.set(event.x.toInt() + screenPosition[0], event.y.toInt() + screenPosition[1])
        }
        false
    }
    setOnClickListener {
        action.invoke(coordinates)
    }
}

Если нужен долгий клик - просто замените setOnClickListener

Я использую, getLocationOnScreen()потому что мне нужны координаты для ViewHolder RecyclerView

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.