OnClickListener - localização x, y do evento?


85

Eu tenho uma visão customizada derivada de View. Gostaria de ser notificado quando a visualização for clicada e o local x, y de onde o clique aconteceu. O mesmo para cliques longos.

Parece que vou fazer isso, preciso substituir onTouchEvent(). Mas não há como obter a localização x, y do evento de um OnClickListener?

Se não, qual é uma boa maneira de saber se um evento de movimento é um clique 'real' versus um clique longo etc? O onTouchEventgera muitos eventos em rápida sucessão etc.

Respostas:


92

Obrigado. Isso era exatamente o que eu estava procurando. Meu código agora é:

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 faz exatamente o que Marcos pediu ...


4
Essas coordenadas são locais para a vista?
Nigel,

7
O manipulador onTouch não deveria retornar falsepara não bloquear eventos de toque? (View.OnTouchListener.onTouch retorna verdadeiro se o ouvinte consumiu o evento, caso contrário, falso.)
ehartwell

5
Bem, não "precisamente" porque OnClickListeneré disparado quando o dedo é liberado, portanto, ACTION_UPmas com limitações: se o gesto de atirar (deslizar) foi executado, OnClickListenernão é disparado, mas ACTION_UPainda será processado.
Alex Semeniuk

Estou tentando escrever um texto nas coordenadas clicadas. Tentei escrever o texto nas coordenadas, (event.getX(), event.getY()) mas não está escrevendo na posição correta.
Prince


26

Exemplo completo

As outras respostas estão faltando alguns detalhes. Aqui está um exemplo 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);
        }
    };
}

Resumo

  • Adicione uma variável de classe para armazenar as coordenadas
  • Salve as coordenadas X, Y usando um OnTouchListener
  • Acesse as coordenadas X, Y no OnClickListener

1
Em vez de um Array flutuante de 2 espaços, um Point () poderia ser usado.
ZooMagic de

O ponto possui X e Y do tipo inteiro. As coordenadas são valores flutuantes. Se eu usar a classe Point, acho que vou perder a precisão ... Sou muito novo no Android e posso ter perdido algo.
mboada

@mboada, você está certo. PointF seria melhor.
Suragch

Deve haver uma maneira de evitar onTouchListener e usar apenas onClickListener. De alguma forma, ContextMenu não precisa disso. Ao clicar em um item e mostrar o menu com a visualização como âncora, ele sabe onde colocá-lo, próximo ao local de toque. Veja aqui: stackoverflow.com/q/57290574/878126 . Você sabe como isso é possível? Em caso afirmativo, considere responder lá.
desenvolvedor Android de

3

Substituir onTouchEvent (MotionEvent ev)

Então você pode fazer:

ev.getXLocation()

Ou algo assim. Tenha um butches.


2
Olá, Tom, sim, podemos usar onTouchEvent, mas precisamos lidar com o discernimento entre cliques e cliques longos, não é? Não faz sentido que eles não forneçam a você uma maneira de saber onde o clique ou o clique longo ocorreu no OnClickListener etc? Obrigado
Marcos

21
Tudo o que você precisa fazer é registrar a posição x e y do último evento ACTION_UP ou ACTION_MOVE e usar esses valores em seu OnClickListener.
Romain Guy

@RomainGuy Mas você também deve calcular a distância entre os dois pontos para determinar um clique. Se você receber o evento ACTION_DOWN em (0,0) e o evento ACTION_UP em (100,100), isso definitivamente não é um clique.
TheRealChx101

@ chx101, o que RomainGuy quis dizer (eu acho) é que se você apenas no touchevent registrar as últimas coordenadas de action_up, então essas são as coordenadas que você pode usar em onclick. no entanto, acho que seria necessário criar uma subclasse da view na prática, ou o onclick não será chamado. você também pode detectar o toque como um detector de gestos em stackoverflow.com/questions/19538747/… answer
Lassi Kinnunen

0

Você pode fazer uma função de extensão em Kotlin, assim:

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

Se você precisar de um clique longo - basta substituir setOnClickListener

Eu uso getLocationOnScreen()porque preciso de coordenadas para ViewHolder do RecyclerView

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.