example - El botón "Mantener presionado" en Android necesita cambiar de estado(selector XML personalizado) usando onTouchListener
touch en android studio (5)
¡Me lo imaginé! Simplemente use view.setSelected()
siguiente manera:
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
yourView.setSelected(true);
...
return true;
}
else if(event.getAction() == MotionEvent.ACTION_UP){
yourView.setSelected(false);
...
return true;
}
else
return false;
}
Eso hará que su selector funcione incluso si su vista tiene un oyente onTouch :)
Tengo un gráfico de botón que debe tener la funcionalidad de "mantener presionado", por lo que en lugar de usar onClickListener, estoy usando onTouchListener para que la aplicación pueda reaccionar.
MotionEvent.ACTION_DOWN,
y
MotionEvent.ACTION_UP
Dependiendo de qué tan rápido se activen esos dos eventos, puedo ejecutar un "pressAndHoldHandler" en el tiempo entre los dos.
De todos modos, cuento largo: tengo numerosos botones "básicos" en la misma aplicación que no requieren la función de presionar y mantener, por lo que están usando onClickListener.
Cada uno de estos botones se ha personalizado gráficamente con su propio archivo de selector XML:
<?xml version="1.0" encoding="UTF-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_enabled="false"
android:drawable="@drawable/btn_chicken_off" />
<item
android:state_enabled="true"
android:state_pressed="true"
android:drawable="@drawable/btn_chicken_s3" />
<item
android:state_enabled="true"
android:state_focused="true"
android:drawable="@drawable/btn_chicken_s2" />
<item
android:state_enabled="true"
android:drawable="@drawable/btn_chicken_off" />
</selector>
Por lo tanto, el problema aquí es: no se puede acceder al selector anterior con onTouchListener. Solo el onClickListener activará los cambios de estado con la sección onClick () de su propio método, por lo que estos botones de "mantener presionado" nunca cambian de estado. Bastante terrible comentario para el usuario.
Actualmente estoy forzando lo anterior dentro del caso de cambio de ACTION_DOWN y ACTION_UP haciendo lo siguiente:
if (action == MotionEvent.ACTION_DOWN) {
btn_chicken.setBackgroundResource(R.drawable.btn_chicken_s3);
}
else
if (action == MotionEvent.ACTION_UP) {
btn_chicken.setBackgroundResource(R.drawable.btn_chicken_off);
}
Pero parece un truco, y falta la etapa de "enfocado pero no presionado".
¿Alguien se tropezó con esto antes?
Asegúrese de devolver false
al final de la función onTouchListener (). :)
Mejor solución:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_activated="true">
<bitmap android:src="@drawable/image_selected"/>
</item>
<item>
<bitmap android:src="@drawable/image_not_selected"/>
</item>
</selector>
@Override
public void onClick(View v) {
if (v.isActivated())
v.setActivated(false);
else
v.setActivated(true);
}
Simplemente puede configurar el botón onClickListener y dejar su método onClick vacío. Su lógica implementa dentro de onTouch. De esa manera tendrás el efecto de prensa.
PS No necesitas todos esos estados en el selector que puedes usar simplemente:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true" android:drawable="@drawable/IMAGE_PRESSED" />
<item android:drawable="@drawable/IMAGE" />
</selector>
Use la función view.setPressed()
para simular el comportamiento presionado por usted mismo.
Probablemente desearía habilitar el estado Presionado cuando obtenga el evento ACTION_DOWN
y deshabilitarlo cuando obtenga el evento ACTION_UP
.
Además, será una buena idea deshabilitarlo en caso de que el usuario salga del botón. Captura el evento ACTION_OUTSIDE
, como se muestra en el siguiente ejemplo:
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
v.setPressed(true);
// Start action ...
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_OUTSIDE:
case MotionEvent.ACTION_CANCEL:
v.setPressed(false);
// Stop action ...
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
break;
}
return true;
}