Botão Android padrão com uma cor diferente


735

Gostaria de mudar ligeiramente a cor de um botão padrão do Android para corresponder melhor à marca de um cliente.

A melhor maneira que encontrei para fazer isso até agora é alterar o Buttondrawable do para o drawable localizado em 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>

Mas fazer isso exige que eu realmente crie três desenháveis ​​diferentes para cada botão que quero personalizar (um para o botão em repouso, um quando focado e outro quando pressionado). Isso parece mais complicado e não SECO do que eu preciso.

Tudo o que realmente quero fazer é aplicar algum tipo de transformação de cor ao botão. Existe uma maneira mais fácil de mudar a cor de um botão do que eu?


Respostas:


724

Descobri que tudo isso pode ser feito em um arquivo com bastante facilidade. Coloque algo como o seguinte código em um arquivo nomeado custom_button.xmle defina background="@drawable/custom_button"na visualização do botão:

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

43
Isso funciona bem para a cor de fundo - você pode definir a cor do texto da mesma maneira?
22410 Rachel

8
Isso me dá "Error: No resource found that matches the given name (at 'color' with value '@color/yellow1')" Essas referências são construídas em cores? Parece que eu preciso de um res / valores / color.xml para fazer este trabalho
Harry Madeira

8
@HarryWood, você precisa definir essas cores em seus res / values ​​/ colors.xml. Como alternativa, substitua-os por "# ff0000", "# 00ff00", para fins de teste @ cfarm54 Esse arquivo deve ser colocado na pasta res / drawable / custom_button.xml @emmby Obrigado pelo trecho de código!
Espinchi 21/05

17
Ótimo ponteiro, obrigado! Observe também para as outras pessoas que estão tentando fazer isso, a ordem dos itens no seletor é significativa. Se você colocar o <item> sem filtro de estado primeiro no arquivo, ele substituirá o restante.
mikerowehl

9
para fazer isso funcionar, coloque custom_button.xml na pasta res / "drawable" - e crie um arquivo res / values ​​/ colors.xml com o seguinte conteúdo: stackoverflow.com/questions/3738886/… - altere os nomes das cores nos dois arquivos para fazê-lo funcionar
sami

308

Seguindo a resposta de Tomasz, você também pode definir programaticamente a tonalidade de todo o botão usando o modo de multiplicação PorterDuff. Isso mudará a cor do botão, e não apenas a tonalidade.

Se você começar com um botão sombreado cinza padrão:

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

lhe dará um botão sombreado vermelho,

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

fornece um botão sombreado verde etc., onde o primeiro valor é a cor no formato hexadecimal.

Ele funciona multiplicando o valor atual da cor do botão pelo valor da cor. Tenho certeza de que também há muito mais que você pode fazer com esses modos.


2
Uau, tentei isso e é totalmente fantástico. Obrigado! Você sabe se existe uma maneira de realizá-lo via xml de alguma forma?
emmby

4
Gente, confira no HTC Desire! Eles têm botões padrão diferentes. Meus botões que usam esse código parecem bastante disponíveis ao definir uma certa largura de layout como "40dp". Com "wrap_content", tudo bem.
OneWorld

5
Confirmada, esta solução não funciona muito bem na interface do usuário do HTC Sense
emmby 21/10/10

19
O Eclipse não mostra isso como uma possível correção:import android.graphics.PorterDuff;
Someone Somewhere

2
Alguém já teve algum problema com isso não funcionando no ICS? Ele não parece trabalho no emulador ou telefone para mim ..
Stev_k

149

Mike, você pode estar interessado em filtros de cores.

Um exemplo:

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

tente isso para obter a cor desejada.


Tente passar nulo no método setColorFilter. Ainda não tentei, mas deve funcionar.
Tomasz

6
@Pacerier para desabilitar: button.getBackground (). ClearColorFilter ();
Stan Kurdziel

3
Eu recomendo pegar uma cor usando a classe Cor: developer.android.com/reference/android/graphics/Color.html
Mugen

Perfeito para temas escuros! Suponho que a outra resposta superior (setColorFilter (0xFFFF0000, PorterDuff.Mode.MULTIPLY)) funcione melhor para temas claros.
Java.is.for.desktop 13/09/14

85

Esta é a minha solução que funciona perfeitamente a partir da API 15 . Esta solução mantém todos os efeitos padrão de clique no botão, como material RippleEffect. Não testei em APIs inferiores, mas deve funcionar.

Tudo o que você precisa fazer é:

1) Crie um estilo que mude apenas colorAccent:

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

Eu recomendo usar ThemeOverlay.AppCompatou o seu principal AppThemecomo pai, para manter o resto de seus estilos.

2) Adicione estas duas linhas ao seu buttonwidget:

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

Às vezes, o seu novo colorAccentnão é exibido no Android Studio Preview, mas quando você inicia o aplicativo no telefone, a cor muda.


Widget Botão de Amostra

<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ão de amostra com cor personalizada


1
O que essa linha faz? "style =" @ style / Widget.AppCompat.Button.Colored ""
Charles Li

2
Isso me ajudou a entender a diferença entre estilo e tema. Obrigado.
rpattabi

2
A resposta aceita está correta, mas muito antiga. Esta é uma resposta simples e mais atualizada.
precisa saber é o seguinte

O problema com esta resposta é que essa configuração colorAccentinfluencia mais do que apenas o segundo plano do botão.
precisa saber é o seguinte

@Blcknx O que, por exemplo?
RedIOne1

61

Agora também é possível usar de appcompat-v7 AppCompatButton com o 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"/>

4
Não funcionou para mim usando o espaço para nome "android:". Mas funcionou quando usei o namespace "app:".
David Velasquez

@ DavidVelasquez Isso funcionou para mim também no Android Lollipop enquanto o android: namespace não mudou nada. Obrigado pela ajuda!
Avinash Prabhakar

Essa é a solução mais simples e deve ser a resposta aceita. Usando o android: backgroundTint funciona para mim.
Ramashish Baranwal

1
Deve estar em app:backgroundTintvez de android:backgroundTintusar o AppCompat.
Hafez Divandari

23

Gosto da sugestão do filtro de cores nas respostas anteriores de @conjugatedirection e @Tomasz; No entanto, descobri que o código fornecido até agora não era tão facilmente aplicado quanto eu esperava.

Primeiro, não foi mencionado onde aplicar e limpar o filtro de cores. É possível que haja outros bons lugares para fazer isso, mas o que me veio à mente foi um OnTouchListener .

Pela minha leitura da pergunta original, a solução ideal seria aquela que não envolva nenhuma imagem. A resposta aceita usando custom_button.xml do @emmby provavelmente é um ajuste melhor do que os filtros de cores, se esse for o seu objetivo. No meu caso, estou começando com uma imagem png de um designer de interface do usuário com a aparência do botão. Se eu definir o plano de fundo do botão para esta imagem, o feedback de realce padrão será perdido completamente. Esse código substitui esse comportamento por um efeito de escurecimento 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();
    }
});

Eu extraí isso como uma classe separada para aplicação em vários botões - mostrada como classe interna anônima apenas para entender.


Essa foi uma ótima solução! Principalmente mesmo efeito que você começa no iOS por padrão, que é o que os designers como :-)
Christer Nordvik

Eu tentei isso com 2 botões na mesma tela com o mesmo fundo e o efeito aplica-se tanto o botão OnTouch
Pateta

16

Se você estiver criando botões coloridos com XML, poderá tornar o código um pouco mais limpo, especificando o estado focado e pressionado em um arquivo separado e reutilizá-los. Meu botão verde fica assim:

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

1
agradável. como fazer com que o estado focado e pressionado se refira às definições padrão do Android para botões?
larham1

Tenho certeza de que não, pois os botões padrão do Android são implementados como bitmaps de 9 patches.
haemish 7/03/12

12

A solução mais curta que funciona com qualquer versão do Android:

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

Notas / Requisitos :

  • Use o app:espaço para nome e não o android:espaço para nome!
  • versão appcompat> 24.2.0

    dependências {compile 'com.android.support:appcompat-v7:25.3.1'}

Explicação : insira a descrição da imagem aqui


1
Curiosamente, para mim app:backgroundTint="@color/my_color"não funcionou. android:backgroundTint="@color/my_color"funcionou perfeitamente embora.
Igor

Esta é a solução mais curta e mais limpa para mim e é tudo.
Marty

11

Eu estou usando essa abordagem

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 você pode ver acima, estou usando um estilo personalizado para o meu botão. A cor do botão corresponde à cor de destaque. Acho essa abordagem muito melhor do que definir, android:backgroundpois não vou perder o efeito cascata que o Google oferece.


8

Existe uma maneira muito mais fácil agora: android-holo-colors.com

Ele permitirá que você altere as cores de todos os desenháveis ​​holo (botões, giradores, ...) facilmente. Você seleciona a cor e, em seguida, baixa um arquivo zip contendo desenhos para todas as resoluções.


8

Use-o desta maneira:

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

4

Em <Button>uso android:background="#33b5e5". ou melhorandroid:background="@color/navig_button"


3

A biblioteca de componentes do DroidUX possui um ColorButtonwidget cuja cor pode ser alterada facilmente, via definição xml e programaticamente em tempo de execução, para que você possa até permitir que o usuário defina a cor / tema do botão, se o seu aplicativo permitir.



2

Você pode definir o tema do seu botão para este

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

1

Uma maneira fácil é apenas definir uma classe Button personalizada que aceite todas as propriedades que você deseja, como raio, gradiente, cor pressionada, cor normal etc. Uma amostra está aqui

Isso é extremamente útil se você tiver muitos botões com as mesmas propriedades, como raio, cor selecionada etc. Você pode personalizar o botão herdado para lidar com essas propriedades adicionais.

Resultado (nenhum seletor de plano de fundo foi usado).

Botão Normal

Imagem normal

Botão pressionado

insira a descrição da imagem aqui


0

A maneira como faço com um botão com estilo diferente que funciona muito bem é subclassificar o objeto Button e aplicar um filtro de cores. Isso também lida com estados ativados e desativados aplicando um alfa ao botão.

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;
        }
    }

}

0

values ​​\ 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>

então:

<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


0

De acordo com as diretrizes de design do material, você precisa usar o estilo como o código abaixo

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

e no layout, adicione esta propriedade ao seu botão

    android:theme="@style/MyButton"

0

É simples .. adicione essa dependência ao seu projeto e crie um botão com 1. Qualquer forma 2. Qualquer cor 3. Qualquer borda 4. Com efeitos materiais

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" />
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.