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.

marca
fuente

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

Vering
fuente
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
Aquí está mi pregunta: stackoverflow.com/questions/40199539/…
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
Suragch
fuente
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.

Al sr
fuente
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

Vitalii Malyi
fuente