OnClickListener - x, y місце події?


85

У мене є власний вигляд, похідний від View. Я хотів би отримувати сповіщення, коли натискається подання, а також місце x, y місця, де стався клік. Те саме для тривалих клацань.

Схоже, це потрібно зробити, мені потрібно перевизначити onTouchEvent(). Чи не існує способу отримати x, y місце події з OnClickListenerзамість цього, однак?

Якщо ні, то який хороший спосіб визначити, чи подія руху - це «справжній» клік проти довгого клацання тощо? onTouchEventГенерує безліч подій у швидкій послідовності і т.д.

Відповіді:


91

Дякую. Це було саме те, що я шукав. Мій код зараз:

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все одно буде оброблений.
Олексій Семенюк

Я намагаюся написати текст на натиснутих координатах. Я намагався писати текст за координатами, (event.getX(), event.getY()) але це не письмо в правильній позиції.
Принц

Ось моє запитання: stackoverflow.com/questions/40199539/…
Принц

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 було б краще.
Сурач

Повинен бути спосіб уникнути 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.
Ромен Гай

@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.