Botón estándar de Android con un color diferente

735

Me gustaría cambiar ligeramente el color de un botón estándar de Android para que coincida mejor con la marca de un cliente.

La mejor manera que he encontrado para hacer esto hasta ahora es cambiar el Buttondibujable por el dibujable ubicado en res/drawable/red_button.xml:

<?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/red_button_pressed" />
    <item android:state_focused="true" android:drawable="@drawable/red_button_focus" />
    <item android:drawable="@drawable/red_button_rest" />
</selector>

Pero hacer eso requiere que realmente cree tres elementos dibujables diferentes para cada botón que quiero personalizar (uno para el botón en reposo, uno cuando está enfocado y otro cuando se presiona). Eso parece más complicado y no SECO de lo que necesito.

Todo lo que realmente quiero hacer es aplicar algún tipo de transformación de color al botón. ¿Hay alguna manera más fácil de cambiar el color de un botón que yo?

emmby
fuente
Y aquí también android.onyou.ch/2011/01/25/…
Pankaj Kumar

Respuestas:

724

Descubrí que todo esto se puede hacer en un archivo con bastante facilidad. Ponga algo como el siguiente código en un archivo llamado custom_button.xmly luego configúrelo background="@drawable/custom_button"en la vista de botones:

<?xml version="1.0" encoding="utf-8"?>
<selector
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true" >
        <shape>
            <gradient
                android:startColor="@color/yellow1"
                android:endColor="@color/yellow2"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="@color/grey05" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>

    <item android:state_focused="true" >
        <shape>
            <gradient
                android:endColor="@color/orange4"
                android:startColor="@color/orange5"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="@color/grey05" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>

    <item>        
        <shape>
            <gradient
                android:endColor="@color/blue2"
                android:startColor="@color/blue25"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="@color/grey05" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>
</selector>
emmby
fuente
43
Eso funciona bien para el color de fondo: ¿puede establecer el color del texto de la misma manera?
Rachel
8
Esto me da "Error: No resource found that matches the given name (at 'color' with value '@color/yellow1')" ¿Estas referencias están construidas en colores? Parece que necesito una res / valores / color.xml para hacer este trabajo
Harry Madera
8
@HarryWood tienes que definir esos colores en tu res / values ​​/ colors.xml. Alternativamente, sustitúyalos por "# ff0000", "# 00ff00", para fines de prueba @ cfarm54. Ese archivo debe colocarse en la carpeta res / drawable / custom_button.xml @emmby ¡Gracias por el fragmento de código!
espinchi
17
Gran puntero, gracias! También tenga en cuenta que para las otras personas que intentan esto, el orden de los elementos en el selector es significativo. Si coloca el <item> sin filtros de estado primero en el archivo, anula el resto.
mikerowehl
99
para que esto funcione, coloque custom_button.xml en su carpeta res / "drawable" y cree un archivo res / values ​​/ colors.xml con estos contenidos: stackoverflow.com/questions/3738886/… - cambie los nombres de color en cualquier archivo para que funcione
sami
308

A partir de la respuesta de Tomasz, también puede configurar mediante programación el tono de todo el botón utilizando el modo de multiplicación PorterDuff. Esto cambiará el color del botón en lugar de solo el tinte.

Si comienza con un botón sombreado gris estándar:

button.getBackground().setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);

te dará un botón sombreado rojo,

button.getBackground().setColorFilter(0xFF00FF00, PorterDuff.Mode.MULTIPLY);

le dará un botón verde sombreado, etc., donde el primer valor es el color en formato hexadecimal.

Funciona multiplicando el valor de color del botón actual por su valor de color. Estoy seguro de que también puedes hacer mucho más con estos modos.

dirección conjugada
fuente
2
Wow, acabo de probarlo y es totalmente fantástico. ¡Gracias! ¿Sabes si hay alguna manera de lograrlo a través de xml de alguna manera?
emmby
44
Chicos, ¡compruébelo en HTC Desire! Tienen diferentes botones estándar. Mis botones que usan este código se ven increíbles cuando se configura un cierto ancho de diseño como "40dp". Con "wrap_content" está bien.
OneWorld
55
Confirmado, esta solución no funciona muy bien en HTC Sense UI
emmby
19
Eclipse no muestra esto como una posible solución:import android.graphics.PorterDuff;
Someone Somewhere
2
¿Alguien ha tenido algún problema con esto que no funciona en ICS? Parece que no funciona en el emulador o el teléfono para mí ..
Stev_k
149

Mike, quizás te interesen los filtros de color.

Un ejemplo:

button.getBackground().setColorFilter(new LightingColorFilter(0xFFFFFFFF, 0xFFAA0000));

prueba esto para lograr el color que deseas.

Tomász
fuente
Intente pasar nulo en el método setColorFilter. No lo he probado pero debería funcionar.
Tomasz
66
@Pacerier para desarmar: button.getBackground (). ClearColorFilter ();
Stan Kurdziel
3
Recomiendo elegir un color usando la clase Color: developer.android.com/reference/android/graphics/Color.html
Mugen
Perfecto para temas oscuros! Supongo que la otra respuesta principal (setColorFilter (0xFFFF0000, PorterDuff.Mode.MULTIPLY)) funciona mejor para temas claros.
java.is.for.desktop
85

Esta es mi solución que funciona perfectamente a partir de API 15 . Esta solución mantiene todos los efectos de clic de botón predeterminados, como material RippleEffect. No lo he probado en API inferiores, pero debería funcionar.

Todo lo que necesitas hacer es:

1) Cree un estilo que solo cambie colorAccent:

<style name="Facebook.Button" parent="ThemeOverlay.AppCompat">
    <item name="colorAccent">@color/com_facebook_blue</item>
</style>

Recomiendo usar ThemeOverlay.AppCompato su main AppThemecomo padre, para mantener el resto de sus estilos.

2) Agregue estas dos líneas a su buttonwidget:

style="@style/Widget.AppCompat.Button.Colored"
android:theme="@style/Facebook.Button"

A veces, su nuevo colorAccentno se muestra en Android Studio Preview, pero cuando inicia su aplicación en el teléfono, el color cambiará.


Widget de botón de muestra

<Button
    android:id="@+id/sign_in_with_facebook"
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:text="@string/sign_in_facebook"
    android:textColor="@android:color/white"
    android:theme="@style/Facebook.Button" />

Botón de muestra con color personalizado

RediOne1
fuente
1
¿Qué hace esta línea? "style =" @ style / Widget.AppCompat.Button.Colored ""
Charles Li
2
Esto me ayudó a comprender la diferencia entre estilo y tema. Gracias.
rpattabi
2
La respuesta aceptada es correcta pero demasiado antigua. Esta es la respuesta más simple y actualizada.
正宗 白 布鞋
El problema con esta respuesta es que esa configuración colorAccentinfluye más que solo el fondo del botón.
Blcknx
@Blcknx ¿Qué por ejemplo?
RediOne1
61

Ahora también puede utilizar de appcompat-v7 AppCompatButton con el backgroundTintatributo:

<android.support.v7.widget.AppCompatButton
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:backgroundTint="#ffaa00"/>
Nilhcem
fuente
44
No funcionó para mí usando el espacio de nombres "android:". Pero funcionó cuando usé el espacio de nombres "app:" en su lugar.
David Velasquez
@DavidVelasquez Eso también funcionó para mí en Android Lollipop mientras que android: namespace no cambió nada. ¡Gracias por la ayuda!
Avinash Prabhakar
Esta es la solución más simple y debería ser la respuesta aceptada. Usar android: backgroundTint funciona para mí.
Ramashish Baranwal 01 de
1
Debe ser en app:backgroundTintlugar de android:backgroundTintcuando se usa AppCompat.
Hafez Divandari
23

Me gusta la sugerencia de filtro de color en respuestas anteriores de @conjugatedirection y @Tomasz; Sin embargo, descubrí que el código proporcionado hasta ahora no se aplicaba tan fácilmente como esperaba.

Primero, no se mencionó dónde aplicar y borrar el filtro de color. Es posible que haya otros buenos lugares para hacer esto, pero lo que me vino a la mente fue un OnTouchListener .

De mi lectura de la pregunta original, la solución ideal sería una que no involucrara ninguna imagen. La respuesta aceptada usando custom_button.xml de @emmby probablemente sea más adecuada que los filtros de color si ese es su objetivo. En mi caso, estoy comenzando con una imagen png de un diseñador de interfaz de usuario de cómo se supone que debe ser el botón. Si configuro el fondo del botón para esta imagen, la retroalimentación de resaltado predeterminada se pierde por completo. Este código reemplaza ese comportamiento con un efecto de oscurecimiento programático.

button.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 0x6D6D6D sets how much to darken - tweak as desired
                setColorFilter(v, 0x6D6D6D);
                break;
            // remove the filter when moving off the button
            // the same way a selector implementation would 
            case MotionEvent.ACTION_MOVE:
                Rect r = new Rect();
                v.getLocalVisibleRect(r);
                if (!r.contains((int) event.getX(), (int) event.getY())) {
                    setColorFilter(v, null);
                }
                break;
            case MotionEvent.ACTION_OUTSIDE:
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                setColorFilter(v, null);
                break;
        }
        return false;
    }

    private void setColorFilter(View v, Integer filter) {
        if (filter == null) v.getBackground().clearColorFilter();
        else {
            // To lighten instead of darken, try this:
            // LightingColorFilter lighten = new LightingColorFilter(0xFFFFFF, filter);
            LightingColorFilter darken = new LightingColorFilter(filter, 0x000000);
            v.getBackground().setColorFilter(darken);
        }
        // required on Android 2.3.7 for filter change to take effect (but not on 4.0.4)
        v.getBackground().invalidateSelf();
    }
});

Extraje esto como una clase separada para la aplicación a múltiples botones, que se muestra como una clase interna anónima solo para entender la idea.

Stan Kurdziel
fuente
¡Esa fue una gran solución! Principalmente el mismo efecto que obtienes en iOS por defecto, que es lo que les gusta a los diseñadores :-)
Christer Nordvik
He intentado esto con 2 botones en la misma pantalla con el mismo fondo y el efecto se aplica tanto al botón en Touch
Goofy
16

Si está haciendo botones de color con XML, puede hacer que el código sea un poco más limpio especificando el estado enfocado y presionado en un archivo separado y reutilizarlos. Mi botón verde se ve así:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_focused="true" android:drawable="@drawable/button_focused"/>
    <item android:state_pressed="true" android:drawable="@drawable/button_pressed"/>

    <item>
        <shape>
            <gradient android:startColor="#ff00ff00" android:endColor="#bb00ff00" android:angle="270" />
            <stroke android:width="1dp" android:color="#bb00ff00" />
            <corners android:radius="3dp" />
            <padding android:left="10dp" android:top="10dp" android:right="10dp" android:bottom="10dp" />
        </shape>
    </item>

</selector>
haemish
fuente
1
bonito. ¿Cómo podría uno hacer que el estado enfocado y presionado vuelva a las definiciones estándar de Android para botones?
larham1
Estoy bastante seguro de que no, ya que los botones estándar de Android se implementan como mapas de bits de 9 parches.
Haemish
12

La solución más corta que funciona con cualquier versión de Android:

<Button
     app:backgroundTint="@color/my_color"

Notas / Requisitos :

  • ¡Use el app:espacio de nombres y no el android:espacio de nombres!
  • versión de appcompat> 24.2.0

    dependencias {compile 'com.android.support:appcompat-v7:25.3.1'}

Explicacion : ingrese la descripción de la imagen aquí

usuario1185087
fuente
1
Curiosamente, para mí app:backgroundTint="@color/my_color"no funcionó. android:backgroundTint="@color/my_color"funcionó perfectamente sin embargo.
Igor
Esta es la solución más corta y limpia para mí y eso es todo.
Marty,
11

Estoy usando este enfoque

style.xml

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:colorPrimaryDark">#413152</item>
    <item name="android:colorPrimary">#534364</item>
    <item name="android:colorAccent">#534364</item>
    <item name="android:buttonStyle">@style/MyButtonStyle</item>
</style>

<style name="MyButtonStyle" parent="Widget.AppCompat.Button.Colored">
    <item name="android:colorButtonNormal">#534364</item>
    <item name="android:textColor">#ffffff</item>
</style>

Como puede ver desde arriba, estoy usando un estilo personalizado para mi botón. El color del botón corresponde al color de acento. Considero que este es un enfoque mucho mejor que la configuración, android:backgroundya que no perderé el efecto dominó que proporciona Google.

Kelok Chan
fuente
8

Hay una manera mucho más fácil ahora: android-holo-colors.com

Le permitirá cambiar los colores de todos los holo dibujables (botones, hiladores, ...) fácilmente. Selecciona el color y luego descarga un archivo zip que contiene dibujos para todas las resoluciones.

Dalmas
fuente
8

Úselo de esta manera:

buttonOBJ.getBackground().setColorFilter(Color.parseColor("#YOUR_HEX_COLOR_CODE"), PorterDuff.Mode.MULTIPLY);
IntelliJ Amiya
fuente
4

En <Button>uso android:background="#33b5e5". o mejorandroid:background="@color/navig_button"

lalitm
fuente
3

La biblioteca de componentes DroidUX tiene un ColorButtonwidget cuyo color se puede cambiar fácilmente, tanto a través de la definición xml como mediante programación en tiempo de ejecución, por lo que incluso puede permitir que el usuario configure el color / tema del botón si su aplicación lo permite.

Ricky Lee
fuente
3

También puede usar esta herramienta en línea para personalizar su botón http://angrytools.com/android/button/ y usar android:background="@drawable/custom_btn"para definir el botón personalizado en su diseño.

JRE.exe
fuente
2

Puede configurar el tema de su botón para esto

<style name="AppTheme.ButtonBlue" parent="Widget.AppCompat.Button.Colored">
 <item name="colorButtonNormal">@color/HEXColor</item>
 <item name="android:textColor">@color/HEXColor</item>
</style>
Manoj Bhadane
fuente
1

Una manera fácil es definir una clase de botón personalizada que acepte todas las propiedades que desee, como radio, gradiente, color presionado, color normal, etc. y luego usar eso en sus diseños XML en lugar de configurar el fondo usando XML. Una muestra está aquí

Esto es extremadamente útil si tiene muchos botones con las mismas propiedades como radio, color seleccionado, etc. Puede personalizar su botón heredado para manejar estas propiedades adicionales.

Resultado (no se utilizó el selector de fondo).

Botón normal

Imagen normal

Botón presionado

ingrese la descripción de la imagen aquí

redDragonzz
fuente
0

La forma en que hago un botón de estilo diferente que funciona bastante bien es subclasificar el objeto Botón y aplicar un filtro de color. Esto también maneja los estados habilitados y deshabilitados aplicando un alfa al botón.

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LightingColorFilter;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.Button;

public class DimmableButton extends Button {

    public DimmableButton(Context context) {
        super(context);
    }

    public DimmableButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DimmableButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @SuppressWarnings("deprecation")
    @Override
    public void setBackgroundDrawable(Drawable d) {
        // Replace the original background drawable (e.g. image) with a LayerDrawable that
        // contains the original drawable.
        DimmableButtonBackgroundDrawable layer = new DimmableButtonBackgroundDrawable(d);
        super.setBackgroundDrawable(layer);
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public void setBackground(Drawable d) {
        // Replace the original background drawable (e.g. image) with a LayerDrawable that
        // contains the original drawable.
        DimmableButtonBackgroundDrawable layer = new DimmableButtonBackgroundDrawable(d);
        super.setBackground(layer);
    }

    /**
     * The stateful LayerDrawable used by this button.
     */
    protected class DimmableButtonBackgroundDrawable extends LayerDrawable {

        // The color filter to apply when the button is pressed
        protected ColorFilter _pressedFilter = new LightingColorFilter(Color.LTGRAY, 1);
        // Alpha value when the button is disabled
        protected int _disabledAlpha = 100;
        // Alpha value when the button is enabled
        protected int _fullAlpha = 255;

        public DimmableButtonBackgroundDrawable(Drawable d) {
            super(new Drawable[] { d });
        }

        @Override
        protected boolean onStateChange(int[] states) {
            boolean enabled = false;
            boolean pressed = false;

            for (int state : states) {
                if (state == android.R.attr.state_enabled)
                    enabled = true;
                else if (state == android.R.attr.state_pressed)
                    pressed = true;
            }

            mutate();
            if (enabled && pressed) {
                setColorFilter(_pressedFilter);
            } else if (!enabled) {
                setColorFilter(null);
                setAlpha(_disabledAlpha);
            } else {
                setColorFilter(null);
                setAlpha(_fullAlpha);
            }

            invalidateSelf();

            return super.onStateChange(states);
        }

        @Override
        public boolean isStateful() {
            return true;
        }
    }

}
Matthew Cawley
fuente
0

valores \ styles.xml

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>

<style name="RedAccentButton" parent="ThemeOverlay.AppCompat.Light">
    <item name="colorAccent">#ff0000</item>
</style>

entonces:

<Button
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="text" />

<Button
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:enabled="false"
    android:text="text" />

<Button
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="text"
    android:theme="@style/RedAccentButton" />

<Button
    style="@style/Widget.AppCompat.Button.Colored"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:enabled="false"
    android:text="text"
    android:theme="@style/RedAccentButton" />

resultado

Milan Hlinák
fuente
0

Según las pautas de diseño de material, debe usar el estilo como se muestra a continuación.

<style name="MyButton" parent="Theme.AppCompat.Light>
    <item name="colorControlHighlight">#F36F21</item>
    <item name="colorControlHighlight">#FF8D00</item>
</style>

y en el diseño, agregue esta propiedad a su botón

    android:theme="@style/MyButton"
Shivam
fuente
0

Es simple ... agregue esta dependencia en su proyecto y cree un botón con 1. Cualquier forma 2. Cualquier color 3. Cualquier borde 4. Con efectos materiales

https://github.com/manojbhadane/QButton

<com.manojbhadane.QButton
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="OK"
       app:qb_backgroundColor="@color/green"
       app:qb_radius="100"
       app:qb_strokeColor="@color/darkGreen"
       app:qb_strokeWidth="5" />
Manoj Bhadane
fuente