programacion - manual de android en pdf
No se pueden manejar los eventos de clic y toque simultáneamente (9)
Estoy tratando de manejar eventos táctiles y hacer clic en eventos en un botón. Yo hago lo siguiente:
button.setOnClickListener(clickListener);
button.setOnTouchListener(touchListener);
Cuando un oyente está registrado, las cosas funcionan bien, pero cuando trato de usarlas, solo se activan los eventos táctiles. Cualquier solución? ¿Qué estoy haciendo mal?
Debería devolver el valor falso en su OnTouchListener
entonces su OnClickListener
también se manejará.
Es un poco complicado.
Si configura onTouchListener
, debe devolver true
en ACTION_DOWN
, para indicar al sistema que he consumido el evento y que no se filtrará a otros oyentes.
Pero entonces OnClickListener
no será despedido.
Así que puedes pensar, solo haré lo mío allí y devolveré el valor false
para que pueda recibir clics también. Si lo haces, funcionará, pero no estarás suscrito a otros eventos táctiles próximos ( ACTION_MOVE
, ACTION_UP
). Por lo tanto, la única opción es regresar allí, pero no recibirás ningún evento de clic como dijimos. previamente.
Por lo tanto, debe realizar el clic manualmente en ACTION_UP
con view.performClick()
Esto funcionará.
Gracias a @urSus por una gran respuesta.
Pero en ese caso, cada toque realizará un clic, incluso ACTION_MOVE
Suponiendo que desee separar move
evento de move
y el evento de click
, puede utilizar un pequeño truco
define un campo boolean
y usa así:
@Override
public boolean onTouch(View view, MotionEvent motionEvent)
{
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
shouldClick = true;
.
.
break;
case MotionEvent.ACTION_UP:
if (shouldClick)
view.performClick();
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
//Do your stuff
shouldClick = false;
break;
}
rootLayout.invalidate();
return true;
}
Hay una diferencia sutil, pero muy importante entre el ClickListener
y el TouchListener
. El TouchListener
se ejecuta antes de que la vista pueda responder al evento. El ClickListener
recibirá su evento solo después de que la vista lo haya manejado.
Por lo tanto, cuando toca su pantalla, TouchListener
se ejecuta el TouchListener
y cuando devuelve true
para su evento, el ClickListener
nunca lo obtendrá. Pero si presiona el trackball de su dispositivo, el ClickListener
debe ser TouchListener
porque el TouchListener
no responderá.
Para hacer que ambos eventos sean posibles en la vista de cuadrícula, solo al hacer que el escucha del tacto sea "falso" de la siguiente manera, esto funcionó para mí.
**GridView myView = findViewById(R.id.grid_view);
myView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// ... Respond to touch events
return false;
}
});**
De esta manera se pueden lograr ambos eventos.
Supongo que estás volviendo true
en tu OnTouchListener
? Eso consumirá el evento por lo que no se enviará hacia abajo para cualquier procesamiento posterior.
En una nota al margen: ¿cuál es el punto de tener tanto un oyente de clic como de toque?
Toda la respuesta anterior dice que no podemos manejar tanto setOnTouchListener
como setOnClickListener
.
Sin embargo, veo que podemos manejar ambos return false
en setOnTouchListener
Ejemplo
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button = findViewById(R.id.button)
button.setOnClickListener {
Log.i("TAG", "onClick")
}
button.setOnTouchListener { v, event ->
Log.i("TAG", "onTouch " + event.action)
false
}
}
Cuando hago clic en el Button
, Logcat se mostrará como
I/TAG: onTouch 0
I/TAG: onTouch 1
I/TAG: onClick
## Exact working solution for both click action and touch listener(dragging) ##
private int initialX;
private int initialY;
private float initialTouchX;
private float initialTouchY;
private float CLICK_ACTION_THRESHOLD = 0.5f;
private float startX;
private float startY;
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (view.getId()) {
case R.id.chat_head_profile_iv:
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//remember the initial position.
initialX = params.x;
initialY = params.y;
startX = event.getX();
startY = event.getY();
//get the touch location
initialTouchX = event.getRawX();
initialTouchY = event.getRawY();
return true;
case MotionEvent.ACTION_UP:
float endX = event.getX();
float endY = event.getY();
if (shouldClickActionWork(startX, endX, startY, endY)) {
openScreen();// WE HAVE A CLICK!!
}
return true;
case MotionEvent.ACTION_MOVE:
//Calculate the X and Y coordinates of the view.
params.x = initialX + (int) (event.getRawX() - initialTouchX);
params.y = initialY + (int) (event.getRawY() - initialTouchY);
//Update the layout with new X & Y coordinate
mWindowManager.updateViewLayout(mChatHeadView, params);
return true;
}
break;
}
return true;
}
private boolean shouldClickActionWork(float startX, float endX, float startY, float endY) {
float differenceX = Math.abs(startX - endX);
float differenceY = Math.abs(startY - endY);
if ((CLICK_ACTION_THRESHOLD > differenceX) && (CLICK_ACTION_THRESHOLD > differenceY))
return true;
else
return false;
}
button.setOnTouchListener(this);
Implementar la interfaz y el código aquí:
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (view.getId()) {
case R.id.send:
switch(motionEvent.getAction()){
case MotionEvent.ACTION_DOWN:
//when the user has pressed the button
//do the needful here
break;
case MotionEvent.ACTION_UP:
//when the user releases the button
//do the needful here
break;
}
break;
}
return false;
}