2012-09-25 21 views
18

Tengo un gráfico de botones que necesita tener la función de "mantener presionado", así que en lugar de usar onClickListener, estoy usando onTouchListener de manera que la aplicación pueda reaccionar aEl botón "Mantener presionado" en Android necesita cambiar los estados (selector XML personalizado) usando onTouchListener

MotionEvent.ACTION_DOWN, 

y

MotionEvent.ACTION_UP 

Dependiendo de la rapidez con que se activan estos dos eventos, que se puede 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 han personalizado gráficamente con su propio archivo XML de selección:

<?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: El selector anterior no consigue acceder con el onTouchListener. Solo onClickListener obtendrá los cambios de estado con la sección onClick() de su propio método, por lo que estos botones "presionar y mantener" nunca cambian de estado. Comentarios bastante terribles para el usuario.

estoy forzando actualmente lo anterior dentro de la caja del interruptor de ACTION_DOWN y ACTION_UP de la siguiente manera:

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 como un corte, y le falta la etapa de "centrado pero no presionado".

¿Alguien ha tropezado con esto antes?

+0

Esto era exactamente mi problema. Gracias por la buena descripción. – Suragch

Respuesta

41

Utilice la función view.setPressed() para simular el comportamiento de presión por usted mismo.

Es probable que desee para que el estado Presionado cuando llegue ACTION_DOWN evento y desactivarlo cuando llegue el evento ACTION_UP.

Además, será una buena idea desactivarlo en caso de que el usuario se deslice fuera del botón.Para controlar 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; 
} 
+2

No creo que se active realmente ACTION_OUTSIDE. Parece ser específicamente para tocar fuera de los cuadros de diálogo. – yincrash

+0

'ACTION_CANCEL' sería un buen lugar para llamar a' view.setPressed (false); ' –

+0

Poner' view.setPressed (false) 'en' MotionEvent.ACTION_UP: 'funcionó para mí. No pude hacer que no funcionara, incluso si me salí de la vista en lugar de solo levantar mi dedo. – Suragch

2

Puede simplemente configurar el botón onClickListener y dejar el método onClick vacío. Su implemento lógico dentro de onTouch. De esa manera tendrá el efecto de prensa.

P.S Usted no necesita todos los del estado en el selector puede simplemente usar:

<?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> 
+0

, lo intenté y no funcionará: onTouch no es un método de OnClickListener. y todavía necesito tener para aquellos que usan una rueda de desplazamiento. alguna otra idea gente? – Octoth0rpe

+0

me refiero a que dejes tu método ontouch tal como está, pero quita el trozo de código que cambia el fondo de él. ADEMÁS, configure la vista en click listener (es decir, yourView.setOnClickListener (nuevo OnClick ....) y déjelo vacío. De esta forma tendrá el efecto de prensa. – Givi

+0

Puedo confirmar que lo anterior no funciona :(@ Octoth0rpe: ¿Encontraste una solución alternativa? –

2

lo he descubierto! Sólo tiene que utilizar view.setSelected() de la 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 va a hacer su trabajo de selección, incluso si su punto de vista tiene un oyente onTouch :)

3

Asegúrese de volver false al final de la función onTouchListener(). :)

1

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); 
} 
Cuestiones relacionadas