744

I'd like to change the color of a standard Android button slightly in order to better match a client's branding.

The best way I've found to do this so far is to change the Button's drawable to the drawable located in 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>

But doing that requires that I actually create three different drawables for each button I want to customize (one for the button at rest, one when focused, and one when pressed). That seems more complicated and non-DRY than I need.

All I really want to do is apply some sort of color transform to the button. Is there an easier way to go about changing a button's color than I'm doing?

Ümañg ßürmån
  • 8,143
  • 4
  • 21
  • 40
emmby
  • 95,927
  • 63
  • 178
  • 243

20 Answers20

736

I discovered that this can all be done in one file fairly easily. Put something like the following code in a file named custom_button.xml and then set background="@drawable/custom_button" in your button view:

<?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
  • 95,927
  • 63
  • 178
  • 243
  • 45
    That works well for background color - can you set the text color in the same way? – Rachel Jul 22 '10 at 12:04
  • where do you get all the colors? – gregm Jul 26 '10 at 19:44
  • you can change those to be whatever you want. You can either change the code to use the hex values directly, or just define your own in colors.xml. – emmby Jul 28 '10 at 20:49
  • Nice post. it lead me to this blog which will probably give a few more lights on the subject: http://blog.androgames.net/40/custom-button-style-and-theme/ – dcarneiro Nov 20 '10 at 21:41
  • 8
    This gives me `"Error: No resource found that matches the given name (at 'color' with value '@color/yellow1')"` Are these references to built in colors? seems I need a res/values/color.xml to make this work – Harry Wood Feb 15 '11 at 12:38
  • @cfarm54 into the drawable/ folder – Artem Russakovskii Apr 07 '11 at 01:23
  • 8
    @HarryWood you have to define those colors in your res/values/colors.xml. Alternatively, substitute them by "#ff0000", "#00ff00", for testing purposes @cfarm54 That file is to be put in the res/drawable/custom_button.xml folder @emmby Thanks for the code snippet! – espinchi May 21 '11 at 20:24
  • 18
    Great pointer, thanks! Also note for the other folks out there trying this, the order of the items in the selector is significant. If you put the with no state filters first in the file it overrides the rest. – mikerowehl Jul 08 '11 at 18:30
  • Certainly is! *"the selection is not based on the "best match," but simply the first item that meets the minimum criteria of the state."* – http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList – ohhorob Jul 08 '11 at 23:28
  • 9
    to make this work, put custom_button.xml in your res/"drawable" folder - and create a file res/values/colors.xml with these contents: http://stackoverflow.com/questions/3738886/android-button-with-different-background-colors/3740351#3740351 - change the color names in either file to make it work – sami Sep 22 '11 at 11:59
  • 1
    Any suggestions for just changing the color? I don't want to change the padding, stroke, or corners. I can't find the 'default' values and leaving them blank creates some ugly buttons. Thanks – Jon May 17 '12 at 12:30
  • Although this is not precisely the answer to your question, in the standard case you just use a custom button with a custom image backing it. See http://ogrelab.ikratko.com/custom-color-buttons-for-android/ and http://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch – imichaelmiers Jun 03 '12 at 19:21
  • hey can anyone tell me, this one file can work for all differen buttons i have in my app ? – Vikas Gupta Oct 31 '12 at 04:35
  • When I use android:state_enabled="false" I would expect findViewById(R.id.Start).setEnabled(false); to change the button to that style, but it does not seem to work. – MikeSchem Jul 07 '15 at 21:45
  • This is the best for me, it fit my needs – Kneelon May 26 '21 at 23:02
310

Following on from Tomasz's answer, you can also programmatically set the shade of the entire button using the PorterDuff multiply mode. This will change the button colour rather than just the tint.

If you start with a standard grey shaded button:

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

will give you a red shaded button,

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

will give you a green shaded button etc., where the first value is the colour in hex format.

It works by multiplying the current button colour value by your colour value. I'm sure there's also a lot more you can do with these modes.

Cristian
  • 191,931
  • 60
  • 351
  • 260
conjugatedirection
  • 3,204
  • 1
  • 12
  • 4
  • Oh, I should add that with this method you won't need 3 drawables, as it applies the colour transform after the highlight/selection. The resulting colour might vary but the colour tint should carry through. – conjugatedirection Aug 15 '10 at 01:42
  • 2
    Wow, just tried that out and it is totally fantastic. Thank you! Do you happen to know if there's a way to accomplish it via xml somehow? – emmby Aug 19 '10 at 20:17
  • 4
    Guys, check it on HTC Desire! They have different standard buttons. My buttons using this code look awefull there WHEN setting a certain layout_width like "40dp". With "wrap_content" it's fine. – OneWorld Sep 22 '10 at 14:08
  • 5
    Confirmed, this solution doesn't work on HTC Sense UI very well – emmby Oct 21 '10 at 15:46
  • Is there a proper documentation for the PorterDuff Mode? Right now I am trying to make a button look black! It's ridiculous... – OneWorld Nov 22 '10 at 13:03
  • For the black button I ended up using the accepted answer. For a red button the porter stuff worked. – OneWorld Nov 22 '10 at 15:00
  • Does anyone know if there's a way to make this work better with custom skins, eg. HTC Sense and Moto-ugly? It would be great to be able to use this solution if we knew it worked universally. – emmby Apr 07 '11 at 14:23
  • 19
    Eclipse doesn't show this as a possible fix: `import android.graphics.PorterDuff;` – Someone Somewhere Oct 28 '11 at 18:14
  • 2
    Has anyone had any problems with this not working in ICS? It doesn't seem to work on the emulator or phone for me.. – Stev_k May 02 '12 at 22:25
  • @emmby I don't have an HTC Sense device available right now, how does it look awful? Is it because the button is dark and the press state should be lighter as opposed to darker? – Stan Kurdziel Jun 17 '12 at 09:38
  • Hex color is normally six hex digits (2 per Red, Green, Blue), but here it is 8 hex digits. Just add two FF to the color you would like to use. – Andy Jun 24 '14 at 06:08
  • @Andy the two first digits are for the opacity. – Marc Plano-Lesay Sep 02 '15 at 11:15
150

Mike, you might be interested in color filters.

An example:

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

try this to achieve the color you want.

Deepak Swami
  • 3,728
  • 1
  • 27
  • 46
Tomasz
  • 3,416
  • 1
  • 19
  • 13
87

This is my solution which perfectly works starting from API 15. This solution keeps all default button click effects, like material RippleEffect. I have not tested it on lower APIs, but it should work.

All you need to do, is:

1) Create a style which changes only colorAccent:

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

I recommend using ThemeOverlay.AppCompat or your main AppTheme as parent, to keep the rest of your styles.

2) Add these two lines to your button widget:

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

Sometimes your new colorAccent isn't showing in Android Studio Preview, but when you launch your app on the phone, the color will be changed.


Sample Button widget

<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" />

Sample Button with custom color

TimD1
  • 903
  • 11
  • 25
RediOne1
  • 9,517
  • 6
  • 23
  • 43
  • 1
    What does this line do? "style="@style/Widget.AppCompat.Button.Colored"" – Charles Li Feb 12 '17 at 21:21
  • 2
    This helped me to understand the difference between style and theme. Thank you. – rpattabi Mar 20 '17 at 12:55
  • 2
    Accepted answer is correct but too old. This one is simple and most up to date answer. – 正宗白布鞋 Mar 07 '18 at 00:43
  • The issue with this answer is, that setting `colorAccent` influences more than just the background of the button. – Blcknx Jun 04 '18 at 07:02
  • @Blcknx What for example? – RediOne1 Jun 04 '18 at 08:10
  • I think fab button, horizontal progress bar, seekbar, radio button, checkbox, switch – Blcknx Jun 04 '18 at 08:28
  • @Blcknx But you create a separate style for a button that does not affect the app style. You can have multiple different styles with different `colorAccent`, one for each Button, Fab, etc. – RediOne1 Jun 04 '18 at 10:08
  • You are right. This limits the effect to the button. Still it's ugly in it's semantics. Android styling is a real mess. Why didn't they just adjust the CSS system? – Blcknx Jun 04 '18 at 10:16
65

You can now also use appcompat-v7's AppCompatButton with the backgroundTint attribute:

<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"/>
Hafez Divandari
  • 6,148
  • 4
  • 32
  • 54
Nilhcem
  • 819
  • 7
  • 7
23

I like the color filter suggestion in previous answers from @conjugatedirection and @Tomasz; However, I found that the code provided so far wasn't as easily applied as I expected.

First, it wasn't mentioned where to apply and clear the color filter. It's possible that there are other good places to do this, but what came to mind for me was an OnTouchListener.

From my reading of the original question, the ideal solution would be one that does not involve any images. The accepted answer using custom_button.xml from @emmby is probably a better fit than color filters if that's your goal. In my case, I'm starting with a png image from a UI designer of what the button is supposed to look like. If I set the button background to this image, the default highlight feedback is lost completely. This code replaces that behavior with a programmatic darkening effect.

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

I extracted this as a separate class for application to multiple buttons - shown as anonymous inner class just to get the idea.

Stan Kurdziel
  • 4,611
  • 1
  • 35
  • 38
  • That was a great solution! Mostly same affect as you get on iOS by default which is what designers like :-) – Christer Nordvik Sep 09 '12 at 19:41
  • i have tried this with 2 button in the same screen with same background and the effect applies to both the button onTouch – Goofy Aug 30 '13 at 07:49
16

If you are making colour buttons with XML you can make the code a bit cleaner by specifying the focused and pressed state in a separate file and reuse them. My green button looks like this:

<?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
  • 416
  • 5
  • 8
  • 1
    nice. how could one make the focused and pressed state refer back to standard android definitions for buttons? – larham1 Feb 13 '12 at 22:22
  • I am pretty sure you don't as the standard Android buttons are implemented as 9-patch bitmaps. – haemish Mar 07 '12 at 17:29
13

The shortest solution which is working with any Android version:

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

Notes/Requirements:

  • Use the app: namespace and not the android: namespace!
  • appcompat version > 24.2.0

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

Explanation: enter image description here

user1185087
  • 3,608
  • 1
  • 22
  • 30
  • 1
    Interestingly, for me `app:backgroundTint="@color/my_color"` did not work. `android:backgroundTint="@color/my_color"` did work perfectly though. – Igor Apr 06 '18 at 19:08
  • This is the shortest and cleanest solution for me and that's all. – Marty May 19 '19 at 10:46
11

I am using this approach

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>

As you can see from above, I'm using a custom style for my button. The button color corresponds to the accent color. I find this a much better approach than setting android:background as I won't lose the ripple effect Google provides.

Kelok Chan
  • 450
  • 6
  • 21
9

Use it in this way:

buttonOBJ.getBackground().setColorFilter(Color.parseColor("#YOUR_HEX_COLOR_CODE"), PorterDuff.Mode.MULTIPLY);
IntelliJ Amiya
  • 70,230
  • 14
  • 154
  • 181
8

There is a much easier way now : android-holo-colors.com

It will let you change the colors of all holo drawables (buttons, spinners, ...) easily. You select the color and then download a zip file containing drawables for all resolutions.

Dalmas
  • 25,439
  • 9
  • 62
  • 75
4

In <Button> use android:background="#33b5e5". or better android:background="@color/navig_button"

lalitm
  • 578
  • 7
  • 11
3

You can Also use this online tool to customize your button http://angrytools.com/android/button/ and use android:background="@drawable/custom_btn" to define the customized button in your layout.

Piyush
  • 23,959
  • 6
  • 36
  • 71
JRE.exe
  • 751
  • 1
  • 13
  • 26
3

The DroidUX component library has a ColorButton widget whose color can be changed easily, both via xml definition and programmatically at run time, so you can even let the user to set the button's color/theme if your app allows it.

Ricky Lee
  • 1,029
  • 6
  • 6
2

You can set theme of your button to this

<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
  • 497
  • 5
  • 10
1

An easy way is to just define a custom Button class which accepts all the properties that you desire like radius, gradient, pressed color, normal color etc. and then just use that in your XML layouts instead of setting up the background using XML. A sample is here

This is extremely useful if you have a lot of buttons with same properties like radius, selected color etc. You can customize your inherited button to handle these additional properties.

Result (No Background selector was used).

Normal Button

Normal Image

Pressed Button

enter image description here

redDragonzz
  • 1,463
  • 1
  • 15
  • 32
0

The way I do a different styled button that works quite well is to subclass the Button object and apply a colour filter. This also handles enabled and disabled states by applying an alpha to the button.

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
  • 2,492
  • 1
  • 24
  • 42
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>

then:

<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" />

result

Milan Hlinák
  • 3,295
  • 1
  • 27
  • 40
0

Per material design guidelines, you need to use the style like below code

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

and in layout add this property to your button

    android:theme="@style/MyButton"
EstevaoLuis
  • 1,902
  • 7
  • 28
  • 35
Shivam
  • 71
  • 2
  • 11
-1

Its simple.. add this dependency in your project and create a button with 1. Any shape 2. Any color 3. Any border 4. With material effects

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
  • 497
  • 5
  • 10