¿Cómo configurar el efecto de clic de botón en Android?

105

En Android, cuando configuro la imagen de fondo en Botón, no puedo ver ningún efecto en el botón.

Necesito algún efecto en el botón para que el usuario pueda reconocer que se hizo clic en ese botón.

El botón debe estar oscuro durante unos segundos cuando se hace clic, entonces, ¿qué debo hacer para esto?

Gracias.

Jignesh Ansodariya
fuente
El siguiente método le permite usar una única clase de estilo para aplicar la máscara a todos sus botones, independientemente de su texto: stackoverflow.com/questions/5327553/…
Zack Marrapese
no No estoy usando el botón de imagen, estoy usando el botón normal de alguna manera fácil para esto?
Jignesh Ansodariya
3
Es un tutorial muy agradable: dibbus.com/2011/02/gradient-buttons-for-android
Pratik Butani

Respuestas:

154

Esto se puede lograr creando un archivo xml dibujable que contenga una lista de estados para el botón. Entonces, por ejemplo, si crea un nuevo archivo xml llamado "button.xml" con el siguiente código:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true" android:state_pressed="false" android:drawable="@drawable/YOURIMAGE" />
    <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/gradient" />
    <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/gradient" />
    <item android:drawable="@drawable/YOURIMAGE" />
</selector>

Para mantener la imagen de fondo con una apariencia oscura en la prensa, cree un segundo archivo xml y llámelo gradient.xml con el siguiente código:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <bitmap android:src="@drawable/YOURIMAGE"/>
    </item>
    <item>
        <shape xmlns:android="http://schemas.android.com/apk/res/android">
            <gradient android:angle="90" android:startColor="#880f0f10" android:centerColor="#880d0d0f" android:endColor="#885d5d5e"/>
        </shape>
    </item>
</layer-list>

En el xml de su botón, configure el fondo para que sea el botón xml, por ejemplo

android:background="@drawable/button"

¡Espero que esto ayude!

Editar: se modificó el código anterior para mostrar una imagen (SUIMAGEN) en el botón en lugar de un color de bloque.

Ljdawson
fuente
Entonces, ¿dónde puedo configurar imagen para el fondo del botón, a Conjunto de imagen es imprescindible
Jignesh Ansodariya
1
Editado para mostrar cómo usar una imagen de fondo con el estado XML. Reemplace YOURIMAGE con el recurso de imagen en su directorio dibujable.
Ljdawson
Esto solo funciona si el src del botón es rectangular. Si el dibujable src tiene alguna forma diferente a esa, el degradado también se aplicará al fondo, y esto es triste.
Renato Lochetti
Realmente no, siempre podría usar una forma diferente en la lista de capas
Ljdawson
2
mientras estoy usando una imagen, funciona para mí ... pero cuando estoy usando un fondo Xml. no funciona ...
DKV
88

Es más simple cuando tiene muchos botones de imagen y no desea escribir xml-s para cada botón.

Versión de Kotlin:

fun buttonEffect(button: View) {
    button.setOnTouchListener { v, event ->
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                v.background.setColorFilter(-0x1f0b8adf, PorterDuff.Mode.SRC_ATOP)
                v.invalidate()
            }
            MotionEvent.ACTION_UP -> {
                v.background.clearColorFilter()
                v.invalidate()
            }
        }
        false
    }
}

Versión de Java:

public static void buttonEffect(View button){
    button.setOnTouchListener(new 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();
                    break;
                }
            }
            return false;
        }
    });
}
András
fuente
2
Utilizo esto en mi código y el único problema que he notado hasta ahora es que el botón se comporta de manera extraña cuando se coloca en un ScrollView.
Finnboy11
Es una solución realmente excelente y esta debería ser la respuesta correcta
Biraj Zalavadia
¿Cómo es esto mejor? El diseño debe mantenerse fuera del código, ¿no?
Errores ocurren
Es solo una solución simple para este problema. Cuando tienes muchos botones y no quieres crear xmls para cada uno, podría ser útil.
András
¡Dios mio! Imagina tener 5 botones en un fragmento ... Tendrás un montón de este código repetitivo ... ¿Cómo refactorizarlo entonces? ¿Cambiar el filtro de color para todos los botones de todas las actividades? En mi humilde opinión, su próximo desarrollador no estará tan feliz ..
Leo Droidcoder
84

Cree su AlphaAnimationObjeto que decida cuánto será el efecto de desvanecimiento del botón, luego déjelo comenzar en el onClickListenerde sus botones

Por ejemplo :

private AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.8F);

// some code

public void onClick(View v) {
    v.startAnimation(buttonClick);
}

por supuesto, esta es solo una forma, no la más preferida, es más fácil

Ahmed Adel Ismail
fuente
5
Lo que me gusta de esta solución es que no requiere la creación de muchos selectores, cuando tienes muchos botones, cada uno con sus propias imágenes personalizadas.
Pete
2
Esto no hace que el botón se desvanezca en un toque hacia abajo, solo lo hace durante una fracción de segundo después de que se detecta el clic y el dedo del usuario ya se ha levantado.
Doug Voss
1
Agradable y simple
@Doug Voss, puede establecer la duración de la animación para hacerla más larga
Ahmed Adel Ismail
¿Qué pasa con onLongClick y 'circularReveal'?
Acauã Pitta
44

Simplemente puede usar el primer plano para Viewlograr un efecto en el que se puede hacer clic:

android:foreground="?android:attr/selectableItemBackground"


Para usar con el tema oscuro, agregue también el tema a su layout(para que el efecto en el que se puede hacer clic sea claro):

android:theme="@android:style/ThemeOverlay.Material.Dark"
Francis
fuente
5
La forma más sencilla de implementar. FYI, atributo android: el primer plano no tiene ningún efecto en los niveles de API inferiores a 23.
dolgom
1
Solución más sencilla.
Jerry Chong
2
Esta debería ser la respuesta aceptada, mucho más simple y agrega el agradable efecto de animación ondulada.
Tyler
1
@dolgom Para el nivel de API <23 úselo en el atributo "background"
Entonces
24

Para que su artículo sea coherente con el aspecto del sistema, intente hacer referencia al atributo del sistema android:attr/selectableItemBackgrounden la etiqueta de fondo o primer plano de la vista deseada:

<ImageView
    ...
    android:background="?android:attr/selectableItemBackground"      
    android:foreground="?android:attr/selectableItemBackground"
    ...
/>

Utilice ambos atributos para obtener el efecto deseado antes / después del nivel de API 23 respectivamente.

https://stackoverflow.com/a/11513474/4683601

Ely Dantas
fuente
2
De lejos, la solución más simple. ¡Gracias!
tykom
9

O usando solo una imagen de fondo, puede lograr el efecto de clic usando setOnTouchListener

Dos caminos

((Button)findViewById(R.id.testBth)).setOnTouchListener(new OnTouchListener() {

      @Override
        public boolean onTouch(View v, MotionEvent event) {
          switch (event.getAction()) {
              case MotionEvent.ACTION_DOWN: {
                  Button view = (Button) v;
                  view.getBackground().setColorFilter(0x77000000, PorterDuff.Mode.SRC_ATOP);
                  v.invalidate();
                  break;
              }
              case MotionEvent.ACTION_UP:
                  // Your action here on button click
              case MotionEvent.ACTION_CANCEL: {
                  Button view = (Button) v;
                  view.getBackground().clearColorFilter();
                  view.invalidate();
                  break;
              }
          }
          return true;
        }
});

ingrese la descripción de la imagen aquí

Y si no quiere usar setOnTouchLister, la otra forma de lograrlo es

    myButton.getBackground().setColorFilter(.setColorFilter(0xF00, Mode.MULTIPLY);

    StateListDrawable listDrawable = new StateListDrawable();
    listDrawable.addState(new int[] {android.R.attr.state_pressed}, drawablePressed);
    listDrawable.addState(new int[] {android.R.attr.defaultValue}, myButton);

    myButton.setBackgroundDrawable(listDrawable);
Vinayak Bevinakatti
fuente
hay errores en el código de la segunda forma. ¿Qué es la función getCurrent ()? Además, myButton no es dibujable, por lo que no se puede agregar como estado.
Ehtesham Hasan
Gracias por indicar el error. Lo he corregido, y myButton es una instancia de la clase Button que proporciona el método setBackgroundDrawable y toma las instancias Drawable, por lo tanto, esto funcionará.
Vinayak Bevinakatti
Mira mi respuesta, que se basa en tu segundo enfoque. stackoverflow.com/a/39430738/5229515
Ehtesham Hasan
Esto probablemente debería tener "return false" al final para que no consuma el evento y se pueda llamar a cualquier onClickListeners adicional.
Doug Voss
3

solo quiero agregar otra manera fácil de hacer esto: si su ImageButton permanece en su fondo y no lo establece en nulo, funcionará como un botón normal y mostrará la animación de clic mientras hace clic exactamente como otros botones. el fondo mientras todavía está allí:

<ImageButton
    android:id="@+id/imageButton2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingBottom="1dp"
    android:paddingLeft="1dp"
    android:paddingRight="1dp"
    android:paddingTop="1dp"
    android:src="@drawable/squareicon" />

Los rellenos no permiten que el fondo sea visible y hacen que el botón actúe como otros botones.

arianoo
fuente
1
esto mantendrá el borde del botón cuadrado alrededor de la imagen si es circular
MSaudi
3

Esta es la mejor solución que se me ocurrió tomando sugerencias de la respuesta de @ Vinayak. Todas las demás soluciones tienen diferentes inconvenientes.

Primero que nada cree una función como esta.

void addClickEffect(View view)
{
    Drawable drawableNormal = view.getBackground();

    Drawable drawablePressed = view.getBackground().getConstantState().newDrawable();
    drawablePressed.mutate();
    drawablePressed.setColorFilter(Color.argb(50, 0, 0, 0), PorterDuff.Mode.SRC_ATOP);

    StateListDrawable listDrawable = new StateListDrawable();
    listDrawable.addState(new int[] {android.R.attr.state_pressed}, drawablePressed);
    listDrawable.addState(new int[] {}, drawableNormal);
    view.setBackground(listDrawable);
}

Explicación:

getConstantState (). newDrawable () se usa para clonar el Drawable existente, de lo contrario se usará el mismo Drawable. Lea más desde aquí: Android: clonación de un elemento de diseño para hacer un StateListDrawable con filtros

mutate () se usa para hacer que el clon de Drawable no comparta su estado con otras instancias de Drawable. Lea más sobre esto aquí: https://developer.android.com/reference/android/graphics/drawable/Drawable.html#mutate ()

Uso:

Puede pasar cualquier tipo de vista (botón, botón de imagen, vista, etc.) como parámetro a la función y se les aplicará el efecto de clic.

addClickEffect(myButton);
addClickEffect(myImageButton);
Ehtesham Hasan
fuente
2
Step: set a button in XML with onClick Action:

 <Button
android:id="@+id/btnEditUserInfo"
style="?android:borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/txt_height"
android:layout_gravity="center"
android:background="@drawable/round_btn"
android:contentDescription="@string/image_view"
android:onClick="edit_user_info"
android:text="Edit"
android:textColor="#000"
android:textSize="@dimen/login_textSize" />

Step: on button clicked show animation point
//pgrm mark ---- ---- ----- ---- ---- ----- ---- ---- -----  ---- ---- -----

    public void edit_user_info(View view) {

        // show click effect on button pressed
        final AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.8F);
        view.startAnimation(buttonClick);

        Intent intent = new Intent(getApplicationContext(),  EditUserInfo.class);
        startActivity(intent);

    }// end edit_user_info
Vinod Joshi
fuente
2

Utilice RippleDrawable para el efecto de estado presionado / hecho clic en Material Design.

Para lograr esto, cree un elemento de ondulación como un .xml en la carpeta / dibujable y úselo en android: background para cualquier vista.

  • Efecto para el icono presionado / hecho clic, use un efecto de onda circular, por ejemplo:

    <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@android:color/darker_gray" />

  • Efecto para la vista en la que se hizo clic con el límite del rectángulo, podemos agregar ondulación sobre el elemento de dibujo existente como se muestra a continuación:

    <?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="#000000"> <item android:drawable="@drawable/your_background_drawable"/> </ripple>

giang nguyen
fuente
2

Por todas las vistas

android:background="?android:attr/selectableItemBackground"

Pero para cardview que tiene uso de elevación

android:foreground="?android:attr/selectableItemBackground"

Para el efecto de clic circular como en la barra de herramientas

android:background="?android:attr/actionBarItemBackground"

También necesitas configurar

 android:clickable="true"
 android:focusable="true"
Faizan Khan
fuente
0

Haciendo una pequeña adición a la respuesta de Andràs:

Puede utilizar postDelayedpara hacer que el filtro de color dure un pequeño período de tiempo para que sea más notable:

        @Override
        public boolean onTouch(final View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    v.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
                    v.invalidate();
                    break;
                }
                case MotionEvent.ACTION_UP: {
                    v.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            v.getBackground().clearColorFilter();
                            v.invalidate();
                        }
                    }, 100L);
                    break;
                }
            }
            return false;
        }

Puede cambiar el valor del retardo 100L para adaptarlo a sus necesidades.

hiddeneyes02
fuente
0

Si está usando un fondo xml en lugar de IMG, simplemente elimine esto:

<item>
    <bitmap android:src="@drawable/YOURIMAGE"/>
</item>

de la primera respuesta que nos dio @Ljdawson.

RastaPopuloS
fuente