OnClickListener - ¿x, y ubicación del evento?


85

Tengo una vista personalizada derivada de Ver. Me gustaría recibir una notificación cuando se haga clic en la vista y la ubicación x, y de donde ocurrió el clic. Lo mismo ocurre con los clics largos.

Parece que para hacer esto, necesito anularlo onTouchEvent(). Sin embargo, ¿no hay forma de obtener la ubicación x, y del evento de an OnClickListener?

Si no es así, ¿cuál es una buena forma de saber si un evento de movimiento es un clic "real" frente a un clic largo, etc.? El onTouchEventgenera muchos eventos en rápida sucesión, etc.

Respuestas:


91

Gracias. Eso era exactamente lo que estaba buscando. Mi código ahora es:

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

que hace precisamente lo que Mark pidió ...


4
¿Son estas coordenadas locales de la vista?
— Nigel

7
¿No debería regresar el controlador onTouch falsepara que no bloquee los eventos táctiles? (View.OnTouchListener.onTouch devuelve verdadero si el oyente ha consumido el evento, falso en caso contrario.)
— ehartwell

5
Bueno, no "precisamente" eso ya que OnClickListenerse dispara cuando se suelta el dedo, por lo tanto, ACTION_UPpero con limitaciones: si se realizó el gesto de deslizar (deslizar), OnClickListenerno se dispara pero ACTION_UPaún se procesará.
— Alex Semeniuk

Estoy intentando escribir texto en las coordenadas en las que se hizo clic. Intenté escribir texto en coordenadas (event.getX(), event.getY()) pero no se escribe en la posición correcta.
— Prince


26

Ejemplo completo

A las otras respuestas les faltan algunos detalles. Aquí tienes un ejemplo completo.

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

Resumen

  • Agregue una variable de clase para almacenar las coordenadas
  • Guarde las coordenadas X, Y usando un OnTouchListener
  • Acceda a las coordenadas X, Y en el OnClickListener

1
En lugar de una matriz flotante de 2 espacios, se podría usar un Point ().
— ZooMagic

El punto tiene X e Y de tipo entero. Las coordenadas son valores flotantes. Si uso la clase Point, creo que voy a perder precisión ... Soy muy nuevo en Android y es posible que me haya perdido algo.
— mboada

@mboada, tienes razón. PointF sería mejor.
— Suragch

Debería haber una forma de evitar onTouchListener y usar solo onClickListener. De alguna manera, ContextMenu no lo necesita. Al hacer clic en un elemento y mostrar el menú con la vista como ancla, sabe dónde colocarlo, cerca de la ubicación táctil. Consulte aquí: stackoverflow.com/q/57290574/878126 . ¿Sabes cómo es posible? Si es así, considere responder allí.
— desarrollador de Android

3

Anular onTouchEvent (MotionEvent ev)

Entonces puedes hacer:

ev.getXLocation()

O algo así. Come butches.


2
Hola Tom, sí, podemos usar onTouchEvent, pero luego debemos manejar el discernimiento entre clics y clics largos nosotros mismos, ¿no es así? ¿No tiene sentido que no le proporcionen una forma de saber dónde tuvo lugar el clic o el clic largo en OnClickListener, etc.? Gracias
— Mark

21
Todo lo que tiene que hacer es registrar la posición x & y del último evento ACTION_UP o ACTION_MOVE y usar estos valores en su OnClickListener.
— Romain Guy

@RomainGuy Pero también debes calcular la distancia entre los dos puntos para determinar un clic. Si recibe el evento ACTION_DOWN en (0,0) y luego el evento ACTION_UP en (100,100) definitivamente no es un clic.
— TheRealChx101

@ chx101, lo que RomainGuy quiso decir (creo) fue que si simplemente al tocar el evento registra las últimas coordenadas de action_up, esas son las coordenadas que puede usar en onclick. sin embargo, creo que sería necesario subclasificar la vista en la práctica, o no se llamará al onclick. también puede detectar el toque como un detector de gestos como en stackoverflow.com/questions/19538747/… respuesta
— Lassi Kinnunen

0

Puede hacer una función de extensión en Kotlin, así:

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

Si necesita un clic largo, simplemente reemplácelo setOnClickListener

Lo uso getLocationOnScreen()porque necesito coordenadas para ViewHolder de RecyclerView

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.