Tengo un problema con mi botón que permanece en un estado resaltado, después de hacer lo siguiente:
public class MainActivity extends AppCompatActivity {
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppCompatButton button = (AppCompatButton) findViewById(R.id.mybutton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Test", "calling onClick");
}
});
button.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
v.invalidate();
break;
}
case MotionEvent.ACTION_UP: {
v.getBackground().clearColorFilter();
v.invalidate();
v.performClick();
Log.d("Test", "Performing click");
return true;
}
}
return false;
}
});
}
}
Con respecto al código anterior, cuando lo uso, espero que el clic del botón se maneje con el tacto, y al devolver "verdadero" el manejo debería detenerse en el touchListener.
Pero este no es el caso. El botón permanece en un estado resaltado, aunque se llame al clic.
Lo que obtengo es:
Test - calling onClick
Test - Performing click
Por otro lado, si estoy usando el siguiente código, se hace clic en el botón, se imprime lo mismo, pero el botón no termina atascado en un estado resaltado:
public class MainActivity extends AppCompatActivity {
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppCompatButton button = (AppCompatButton) findViewById(R.id.mybutton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Test", "calling onClick");
}
});
button.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
v.invalidate();
break;
}
case MotionEvent.ACTION_UP: {
v.getBackground().clearColorFilter();
v.invalidate();
// v.performClick();
Log.d("Test", "Performing click");
return false;
}
}
return false;
}
});
}
}
Estoy un poco confundido sobre cuál es la cadena de respuesta al evento táctil. Mi conjetura es que es:
1) TouchListener
2) ClickListener
3) ParentViews
¿Alguien puede confirmar esto también?
android
onclicklistener
android-button
ontouchlistener
Oso blanco
fuente
fuente
Respuestas:
Dichas personalizaciones no necesitan modificaciones programáticas. Puedes hacerlo simplemente en
xml
archivos. En primer lugar, elimine elsetOnTouchListener
método que proporciona en suonCreate
totalidad. A continuación, defina un color selector en elres/color
directorio como el siguiente. (si el directorio no existe, créelo)res / color / button_tint_color.xml
Ahora, configúrelo en el
app:backgroundTint
atributo del botón :Resultado visual:
EDITADO: (para abordar el problema del evento táctil)
Desde un punto de vista general, el flujo del evento táctil comienza desde
Activity
, luego fluye hacia el diseño (desde los diseños principales hasta los secundarios) y luego hacia las vistas. (Flujo LTR en la siguiente imagen)Cuando el evento tacto llega a la vista de destino, la vista puede controlar el evento luego decidir pasarlo a los diseños antes / actividad o no (volviendo
false
detrue
enonTouch
el método). (Flujo RTL en la imagen de arriba)Ahora echemos un vistazo al código fuente de la Vista para obtener una visión más profunda de los flujos de eventos táctiles. Al echar un vistazo a la implementación de la
dispatchTouchEvent
, veremos que si configuras unaOnTouchListener
vista y luego regresastrue
en suonTouch
método,onTouchEvent
no se llamará a la vista.Ahora, mire el
onTouchEvent
método donde está la acción del eventoMotionEvent.ACTION_UP
. Vemos que la acción de hacer clic ocurre allí. Por lo tanto, regresartrue
en elOnTouchListener
'sonTouch
y, en consecuenciaonTouchEvent
, no llamar alOnClickListener
' hace que no se llame al 'sonClick
.Hay otro problema con no llamar al
onTouchEvent
, que está relacionado con el estado presionado y que mencionó en la pregunta. Como podemos ver en el siguiente bloque de código, hay una instancia deUnsetPressedState
esas llamadas cuando se ejecuta. El resultado de no llamar es que la vista se atasca en el estado presionado y su estado de dibujo no cambia.setPressed
(false)
setPressed(false)
UnsetPressedState :
Con respecto a las descripciones anteriores, puede cambiar el código llamándose a
setPressed(false)
sí mismo para cambiar el estado dibujable donde está la acción del eventoMotionEvent.ACTION_UP
:fuente
Now, look at the onTouchEvent method where the event action is MotionEvent.ACTION_UP. We see that perform-click action happens there. So, returning true in the OnTouchListener's onTouch and consequently not calling the onTouchEvent, causes not calling the OnClickListener's onClick.
en mi caso se llama a onClick mUnsetPressedState comprueba si es nulo antes de establecerlo en falso y tampoco se puede ejecutar el ejecutable si estamos preimpresos. Yo no entiendo muy bien cómo se deduce que debe establecerse en falseonClick
llama porque estás llamandov.performClick();
. Compruebe el código anterior en laMotionEvent.ACTION_UP
sección nuevamente,setPressed(false)
se llama de todos modos, simUnsetPressedState
es nulo o no, siprepressed
es verdadero o no. La diferencia está en la forma de llamar asetPressed(false)
que podría ser a través depost
/postDelayed
o directamente.Estás jugando
touch
yfocus
eventos. Comencemos por comprender el comportamiento con el mismo color. De manera predeterminada, seSelector
asigna como fondo aButton
Android. Entonces, simplemente cambiando el color de fondo, make es estático (el color no cambiará). Pero no es un comportamiento nativo.Selector
podría parecerse a este.Como puede ver arriba, hay estado
focused
y estadopressed
. Al configuraronTouchListener
, manejará los eventos táctiles, que no tienen nada que verfocus
.Selector
del botón debe reemplazar elfocus
evento con un eventotouch
durante el clic en el botón. Pero en la primera parte de su código, interceptó eventos para eltouch
(retorno verdadero de la devolución de llamada). El cambio de color no puede continuar y se congela con el mismo color. Y es por eso que la segunda variante (sin intercepción) está funcionando bien y esa es su confusión.ACTUALIZAR
Todo lo que necesita hacer es cambiar el comportamiento y el color de la
Selector
. Por ej. utilizando el siguiente fondo para elButton
. Y eliminaronTouchListener
de su implementación en absoluto.fuente
onTouchListener
s como desee. Simplemente no necesita consumir eventos, porreturn true
.backgroundColor
.Si asigna un fondo al botón, no cambiará el color al hacer clic.
y configúralo como fondo para tu botón
fuente
solo puede usar chips de material para en lugar de la vista de botones. consulte: https://material.io/develop/android/components/chip allí manejan esos eventos hililghted y puede personalizar con la aplicación de los temas.
fuente