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
Suragch
источник
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

Виталий Малый
источник