OnClickListener - x, y lokalizacja zdarzenia?

85

Mam niestandardowy widok pochodzący z widoku. Chcę otrzymywać powiadomienia o kliknięciu widoku oraz o miejscu x, y miejsca kliknięcia. To samo dotyczy długich kliknięć.

Wygląda na to, że muszę to zrobić, muszę zmienić onTouchEvent(). Czy OnClickListenerzamiast tego nie ma sposobu, aby uzyskać lokalizację x, y zdarzenia z an ?

Jeśli nie, jaki jest dobry sposób na stwierdzenie, czy zdarzenie ruchu jest „prawdziwym” kliknięciem, czy długim kliknięciem itp.? onTouchEventGeneruje wiele wydarzeń w krótkim odstępie czasu itd.

znak
źródło

Odpowiedzi:

91

Dziękuję Ci. To było dokładnie to, czego szukałem. Mój kod to teraz:

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

który robi dokładnie to, o co prosił Mark ...

Vering
źródło
4
Czy te współrzędne są lokalne dla widoku?
Nigel
7
Czy moduł obsługi onTouch nie powinien powrócić, falseaby nie blokował zdarzeń dotykowych? (View.OnTouchListener.onTouch zwraca wartość true, jeśli odbiornik wykorzystał zdarzenie, w przeciwnym razie false).
ehartwell
5
No cóż, nie "dokładnie", ponieważ OnClickListenerjest uruchamiany po zwolnieniu palca, więc w tym przypadku, ACTION_UPale z ograniczeniami: jeśli wykonano gest machnięcia (machnięcia), OnClickListenerto nie jest uruchamiany, ale ACTION_UPnadal będzie przetwarzany.
Alex Semeniuk
Próbuję napisać tekst na klikniętych współrzędnych. Próbowałem pisać tekst ze współrzędnymi, (event.getX(), event.getY()) ale nie jest to pismo we właściwej pozycji.
Prince
Oto moje pytanie: stackoverflow.com/questions/40199539/…
Prince
26

Pełny przykład

W innych odpowiedziach brakuje niektórych szczegółów. Oto pełny przykład.

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

Podsumowanie

  • Dodaj zmienną klasy do przechowywania współrzędnych
  • Zapisz współrzędne X, Y za pomocą pliku OnTouchListener
  • Uzyskaj dostęp do współrzędnych X, Y w OnClickListener
Suragch
źródło
1
Zamiast 2 spacji float Array, można użyć Point ().
ZooMagic
Punkt ma X i Y typu całkowitego. Współrzędne są wartościami zmiennoprzecinkowymi. Myślę, że jeśli użyję klasy Point, stracę precyzję… Jestem bardzo nowy w Androidzie i być może coś mi umknęło.
mboada
@mboada, masz rację. PointF byłoby lepsze.
Suragch
Powinien istnieć sposób, aby uniknąć onTouchListener i używać tylko onClickListener. W jakiś sposób ContextMenu tego nie potrzebuje. Po kliknięciu elementu i wyświetleniu menu z widokiem jako kotwicą wie, gdzie go umieścić, w pobliżu miejsca dotknięcia. Zobacz tutaj: stackoverflow.com/q/57290574/878126 . Czy wiesz, jak to możliwe? Jeśli tak, rozważ odpowiedź tam.
programista Androida
3

Zastąp onTouchEvent (MotionEvent ev)

Następnie możesz:

ev.getXLocation()

Czy coś takiego. Miej pupy.

Do Pana
źródło
2
Cześć Tom, tak, możemy użyć onTouchEvent, ale wtedy musimy sami poradzić sobie z rozróżnianiem między kliknięciami a długimi kliknięciami, prawda? To nie ma sensu, że nie zapewniają Ci sposobu, aby dowiedzieć się, gdzie miało miejsce kliknięcie lub długie kliknięcie w OnClickListener itp.? Dzięki
Mark
21
Wszystko, co musisz zrobić, to zarejestrować pozycję x & y ostatniego zdarzenia ACTION_UP lub ACTION_MOVE i użyć tych wartości w swoim OnClickListener.
Romain Guy
@RomainGuy Ale musisz także obliczyć odległość między dwoma punktami, aby określić kliknięcie. Jeśli otrzymasz zdarzenie ACTION_DOWN o (0,0), a następnie zdarzenie ACTION_UP o (100,100), to zdecydowanie nie jest kliknięcie.
TheRealChx101
@ chx101, RomainGuy miał na myśli (myślę), że jeśli tylko na touchevent zapiszesz ostatnie współrzędne action_up, to są to współrzędne, których możesz użyć w onclick. jednak myślę, że wymagałoby to podklasy widoku w praktyce, w przeciwnym razie onclick nie zostanie wywołany. możesz także wykryć kran jako wykrywacz gestów, jak na stackoverflow.com/questions/19538747/ ... odpowiedź
Lassi Kinnunen
0

Możesz utworzyć funkcję rozszerzenia w Kotlinie, na przykład:

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

Jeśli potrzebujesz długiego kliknięcia - po prostu wymień setOnClickListener

Używam, getLocationOnScreen()ponieważ potrzebuję współrzędnych dla ViewHolder RecyclerView

Vitalii Malyi
źródło