Coloring Buttons in Android with Material Design and AppCompat
Solution 1
Officially fixed in Support Library rev.22 (Fri March 13, 2015). See relevant google code issue:
https://issuetracker.google.com/issues/37008632
Usage example
theme.xml:
<item name="colorButtonNormal">@color/button_color</item>
v21/theme.xml
<item name="android:colorButtonNormal">@color/button_color</item>
Solution 2
Edit (22.06.2016):
Appcompat library started to support material buttons after I posted the original response. In this post you can see the easiest implementation of raised and flat buttons.
Original Answer:
Since that AppCompat doesn't support the button yet you can use xml as backgrounds. For doing that I had a look at the source code of the Android and found the related files for styling material buttons.
1 - Look at the original implementation of material button from source.
Have a look at the btn_default_material.xml on android source code.
You can copy the file into your projects drawable-v21 folder. But don't touch the color attr here. The file you need to change is the second file.
drawable-v21/custom_btn.xml
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item android:drawable="@drawable/btn_default_mtrl_shape" />
</ripple>
2 - Get the shape of the original material button
As you realise there is a shape used inside this drawable which you can find in this file of the source code.
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/button_inset_horizontal_material"
android:insetTop="@dimen/button_inset_vertical_material"
android:insetRight="@dimen/button_inset_horizontal_material"
android:insetBottom="@dimen/button_inset_vertical_material">
<shape android:shape="rectangle">
<corners android:radius="@dimen/control_corner_material" />
<solid android:color="?attr/colorButtonNormal" />
<padding android:left="@dimen/button_padding_horizontal_material"
android:top="@dimen/button_padding_vertical_material"
android:right="@dimen/button_padding_horizontal_material"
android:bottom="@dimen/button_padding_vertical_material" />
</shape>
3 - Getting dimensions of the material button
And in this file you there are some dimensions used from the file that you can find here. You can copy the whole file and put into your values folder. This is important for applying the same size (that is used in material buttons) to all buttons
4 - Create another drawable file for old versions
For older versions you should have another drawable with the same name. I am directly putting the items inline instead of referencing. You may want to reference them. But again, the most important thing is the original dimensions of the material button.
drawable/custom_btn.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- pressed state -->
<item android:state_pressed="true">
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/button_inset_horizontal_material"
android:insetTop="@dimen/button_inset_vertical_material"
android:insetRight="@dimen/button_inset_horizontal_material"
android:insetBottom="@dimen/button_inset_vertical_material">
<shape android:shape="rectangle">
<corners android:radius="@dimen/control_corner_material" />
<solid android:color="@color/PRESSED_STATE_COLOR" />
<padding android:left="@dimen/button_padding_horizontal_material"
android:top="@dimen/button_padding_vertical_material"
android:right="@dimen/button_padding_horizontal_material"
android:bottom="@dimen/button_padding_vertical_material" />
</shape>
</inset>
</item>
<!-- focused state -->
<item android:state_focused="true">
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/button_inset_horizontal_material"
android:insetTop="@dimen/button_inset_vertical_material"
android:insetRight="@dimen/button_inset_horizontal_material"
android:insetBottom="@dimen/button_inset_vertical_material">
<shape android:shape="rectangle">
<corners android:radius="@dimen/control_corner_material" />
<solid android:color="@color/FOCUSED_STATE_COLOR" />
<padding android:left="@dimen/button_padding_horizontal_material"
android:top="@dimen/button_padding_vertical_material"
android:right="@dimen/button_padding_horizontal_material"
android:bottom="@dimen/button_padding_vertical_material" />
</shape>
</inset>
</item>
<!-- normal state -->
<item>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/button_inset_horizontal_material"
android:insetTop="@dimen/button_inset_vertical_material"
android:insetRight="@dimen/button_inset_horizontal_material"
android:insetBottom="@dimen/button_inset_vertical_material">
<shape android:shape="rectangle">
<corners android:radius="@dimen/control_corner_material" />
<solid android:color="@color/NORMAL_STATE_COLOR" />
<padding android:left="@dimen/button_padding_horizontal_material"
android:top="@dimen/button_padding_vertical_material"
android:right="@dimen/button_padding_horizontal_material"
android:bottom="@dimen/button_padding_vertical_material" />
</shape>
</inset>
</item>
</selector>
Result
Your button will have ripple effect on Lollipop devices. The old versions will have exactly same button except the ripple effect. But since that you provide drawables for different states, they'll also respond to touch events (as the old way).
Solution 3
This has been enhanced in v23.0.0 of AppCompat library with the addition of more themes including
Widget.AppCompat.Button.Colored
First of all include appCompat dependency if you haven't already
compile('com.android.support:appcompat-v7:23.0.0') {
exclude group: 'com.google.android', module: 'support-v4'
}
now since you need to use v23 of the app compat, you'll need to target SDK-v23 as well!
compileSdkVersion = 23
targetSdkVersion = 23
In your values/theme
<item name="android:buttonStyle">@style/BrandButtonStyle</item>
In your values/style
<style name="BrandButtonStyle" parent="Widget.AppCompat.Button.Colored">
<item name="colorButtonNormal">@color/yourButtonColor</item>
<item name="android:textColor">@color/White</item>
</style>
In your values-v21/style
<style name="BrandButtonStyle" parent="Widget.AppCompat.Button.Colored">
<item name="android:colorButtonNormal">@color/yourButtonColor</item>
<item name="android:textColor">@color/White</item>
</style>
Since your button theme is based on Widget.AppCompat.Button.Colored
The text color on the button is by default white!
but it seems there is an issue when you disable the button, the button will change its color to light grey, but the text color will remain white!
a workaround for this is to specifically set the text color on the button to white! as I have done in the style shown above.
now you can simply define your button and let AppCompat do the rest :)
<Button
android:layout_width="200dp"
android:layout_height="48dp" />
Edit:
To add <Button android:theme="@style/BrandButtonStyle"/>
Solution 4
In Android Support Library 22.1.0, Google made the Button
tint aware.
So, another way to customise the background color of button is to use the backgroundTint
attribute.
For example,
<Button
android:id="@+id/add_remove_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/bg_remove_btn_default"
android:textColor="@android:color/white"
tools:text="Remove" />
Solution 5
To support colored buttons use the latest AppCompat library (>23.2.1) with:
inflate - XML
AppCompat Widget:
android.support.v7.widget.AppCompatButton
AppCompat Style:
style="@style/Widget.AppCompat.Button.Colored"
NB! To set a custom color in xml: use the attr: app
instead of android
(use alt+enter
or declare xmlns:app="http://schemas.android.com/apk/res-auto"
to use app
)
app:backgroundTint="@color/your_custom_color"
Example:
<android.support.v7.widget.AppCompatButton
style="@style/Widget.AppCompat.Button.Colored"
app:backgroundTint="@color/your_custom_color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Colored Button"/>
or set it programmatically - JAVA
ViewCompat.setBackgroundTintList(your_colored_button,
ContextCompat.getColorStateList(getContext(),R.color.your_custom_color));
Related videos on Youtube
mail929
Updated on January 15, 2021Comments
-
mail929 over 3 years
Before the
AppCompat
update came out today I was able to change the color of buttons in Android L but not on older versions. After including the new AppCompat update I am unable to change the color for either version, when I do try the button just disappears. Does anyone know how to change the button color?The following pictures shows what I want to achieve:
The white button is default, the red one is what I want.
This is what I was doing previously to change the color of the buttons in the
styles.xml
:<item name="android:colorButtonNormal">insert color here</item>
and to do it dynamically:
button.getBackground().setColorFilter(getResources().getColor(insert color here), PorterDuff.Mode.MULTIPLY);
Also I did change the theme parent from
@android:style/Theme.Material.Light.DarkActionBar
toTheme.AppCompat.Light.DarkActionBar
-
Informatic0re over 9 yearsI tried the same but nothing changed the color of the Button. I also removed android: from the attribute becouse it is from the support lib and not part of android namespace
-
Informatic0re over 9 yearsIf you are using android:colorButtonNormal with Android 5.0 it works - but it seems not to be backwards compatible
-
mail929 over 9 yearsYes that is exactly what I was experiencing
-
Informatic0re over 9 yearsI also figured out that the accent color does not change the CheckBox color, but it does in older versions
-
theapache64 about 8 yearsplus one for that dynamic method. :)
-
-
fernandohur over 9 yearsSo after implementing this, we just add
android:background="@drawable/custom_btn"
to our button? -
eluleci over 9 yearsYes exactly. If you use the same background for all buttons and if you don't want to add this again and again, define a button style in your styles.xml <style name="ButtonStyle" parent="android:Widget.Button"> <item name="android:background">@drawable/custom_btn</item> </style> and add button style in your theme <item name="android:buttonStyle">@style/ButtonStyle</item>
-
xakpc over 9 yearshow can i add elevation to this button on pre-21? as i understand i should add new shape with shadow below button, but where exactly i should put it?
-
eluleci over 9 yearsthe shadow should be added to drawables for each state. ex: <!-- pressed state --> <item android:state_pressed="true"> <!-- include the drawable that contains shadow --> </item>
-
Sam over 9 yearsVery annoying that this isn't supported out of the box
-
eluleci over 9 yearsI totally agree with you. Button is the mostly used widget but it is not included in the support library for material. I wonder what they were thinking.
-
JMRboosties about 9 yearsIt's unclear to me how to set the color for a single instance of the button. For example, I want most of my buttons to just be the standard grey, but a specific button to be red. Setting
colorButtonNormal
in the main theme will obviously make all buttons red, but when I try to includecolorButtonNormal="@color/red"
in the style which the button uses, this is ignored. What is the correct way to do this? I don't think having a differentbtn_default_mtrl_shape
file for each color you may use is practical... -
JMRboosties about 9 yearsAlso, following your guide it seems that the background isn't showing up at all...
-
theblang about 9 yearsIf you don't want to change any of the "tint" colors or selected colors this is definitely an easy solution to still get a feedback with colored buttons. Thanks!
-
ZakTaccardi about 9 years@JMRboosties I am having the same problem. Did you find a solution?
-
JMRboosties about 9 yearsI ended up getting it to work, the guide is fine. At step 2, you might want to hardcode the color resource directly into the shape's solid color instead of relying on a ?attr. I was trying to use a value from ?attr but was doing it wrong.
-
ScouseChris about 9 yearsHas anyone else noticed the drop shadow effect disappears when using a
shape
drawable in theripple
but not if you set a colour directly? -
Igoussam about 9 yearsIs there any example how to use it? How can I set colors on just one Button?
-
WindRider about 9 yearsI updated the answer with the attribute definitions that i use and know they work.
-
dominik4142 about 9 years@WindRider I have a problem though, I want to use it to create buttons with different colors. I create styles Button.Red, Button.Green, all with parent equals Button base style. I set item colorButtonNormal to requested color, set this as button theme. Unfortunately it only colours buttons for 21. Below it does not override colorButtonNormal defined in theme.
-
WindRider about 9 yearsWhat parent style do you use? Check that all your styles contain colorButtonNormal for <v21 and android:colorButtonNormal for v21. Looks like you only have the second defined. Just a give me a pastebin with your styles.
-
Greg Ennis about 9 years@WindRider Unfortunately I'm having the same issue. When applying theme directly to a button, like
<Button android:theme="@style/RedButton"... />
, the theme only gets applied for v21. (If I put the colors in the app-wide theme definitions, it works for all API levels, but I cant do that because I need buttons with different colors). Seems like a bug in appcompat to me. -
Greg Ennis about 9 years@dominik4142 did you find a solution for this? (see my comment above)
-
WindRider about 9 yearsGreg, shouldn't it be <Button style="@style/RedButton"... /> instead?
-
dominik4142 about 9 years@WindRider you didn't mention me and I didn't get any notification. This is what I found out: In order for this styling to work, I need to set theme:= of the button. This works nicely on >21. Unfortunately, this doesn't seem to bother lower versions. They are bothered only by settings colorButtonNormal in app theme. Because I want to achieve different button colors, your solution doesn't help me much.
-
dominik4142 about 9 years@GregEnnis I totally agree, same for me. I worked it around by replacing button background on lower versions (this were very small contextual buttons used in one place so I could afford that). I simply used theme= and style= both on one button, theme to apply colouring on >21, style override in both <21 (background + margins) and >21 (empty to disable <21 background replacement).
-
Greg Ennis about 9 years@WindRider - no it should not. android:theme is required here. As I mentioned, it works on v21, so that is not the problem. It sounds like you have it working - can you post a working sample?
-
GuillermoMP about 9 yearsFinally! Blog post about the 22.1 release: android-developers.blogspot.no/2015/04/…
-
Stephane Maarek about 9 yearsDocumentation says: "This will automatically be used when you use Button in your layouts. You should only need to manually use this class when writing custom views." developer.android.com/reference/android/support/v7/widget/… does this mean we don't have to manually change all of our layouts and java code?
-
Anton Holovin about 9 years@Stephane no, we should change layouts. chris.banes.me/2015/04/22/support-libraries-v22-1-0
-
swooby about 9 yearsAWESOME! Now, is there a AppCompatToggleButton that lets you change the background of ToggleButtons? Maybe I can plagiarize the code...
-
Daniel Gomez Rico about 9 yearsDont work for
Base.Widget.AppCompat.Button
inCompat 22.1.1
-
hunyadym about 9 yearsWith AppCompat 22.1.1 it works for me on 2.3.7, 4.4.4 and 5.1 too for one button only: setting button's
android:theme="@style/ColoredButton"
, and in styles.xml<style name="ColoredButton" parent="Widget.AppCompat.Button"> <item name="colorButtonNormal">@color/button_yellow</item> </style>
-
JJD about 9 yearsAndroid Support Library 22.1.1 has been released. A changelog is pending.
-
Juan Saravia almost 9 yearsThanks!!! I just changed the parent value for "Widget.AppCompat.EditText" as I need to update the EditText style.
-
Timur_C almost 9 yearsUnfortunately this works only on API 21+. The android:backgroundTint attribute doesn't work on pre-Lollipop even with AppCompat library. Only colorButtonNormal from theme works on pre-Lollipop.
-
Dave Jensen almost 9 yearsThis plus the link to the blog post is the answer. @mail929 it would be great if you could update the answer as such.
-
Natix almost 9 yearsHow do you change the text color (for example to white)?
-
gladed almost 9 years@hunyadym, adding a theme to the button breaks onClick for some reason. I would classify this as a workaround until the Design library provides a better way.
-
hunyadym almost 9 years@gladed: It seems in your case the problem is this bug: code.google.com/p/android/issues/detail?id=62795#c1
-
Rachel almost 9 yearsThank you, worked for me as well. Make sure to use
android:theme
and notstyle
. You can also addcolorControlHighlight
andcolorControlActivated
. -
Rachel almost 9 years@gladed I have the same issue. Did you manage to find a good workaround?
-
Rachel almost 9 years@gladed My current workaround is to set the OnClickListener programmatically.
-
gladed almost 9 years@Rachel another way is to use AppCompatButton and programmatically set the background tint modes but this is very messy. The way you are doing it is probably the best we can do for now.
-
Shajeel Afzal almost 9 yearsIt is not working, the AppCompat library version is
22.2.0
-
Andrey Uglev almost 9 yearsdoes't work, API 22, AppCompatActivity, theme Material.Light
-
Artem almost 9 years@AndreyUglev try to use
Theme.AppCompat.Light
instead. -
Aron Lorincz almost 9 years@hunyadym I can confirm it works just fine! The answer should be edited!
-
Amio.io almost 9 yearsHi, it changes the desired color BUT removes the shadows.
-
Amio.io almost 9 yearsHi, it changes the desired color BUT removes the shadows.
-
Amio.io over 8 yearsHi again, I can see. It's proper behaviour now.
-
Amio.io over 8 yearsHi again, I can see. It's proper behaviour now.
-
mohlendo over 8 yearsThat's the best way to do it, now! You can also use the style on individual buttons with
<Button android:theme="@style/BrandButtonStyle"/>
. It has to be thetheme
attribute and not thestyle
attribute. -
Bresiu over 8 years@Muhammad Alfaifi Do you have sample project or gist for this? I've created clean project and it does not work: github.com/Bresiu/ThemeTest. In Lolipop button colors with accent color and on API v16, button remains gray: i.imgur.com/EVwkpk2.png
-
Kamil Nękanowicz over 8 yearsIt helps only partially, setEnabled(false) no effect
-
Kamil Nękanowicz over 8 yearsIt helps only partially, setEnabled(false) no effect
-
Ray Hunter over 8 yearsThis only worked fro me when specifying the attribute android:theme. I could not get the attribute style to work for me with the button tag.
-
Pratik Butani over 8 years
compile 'com.android.support:appcompat-v7:23.1.0'
You must have to add. -
Patrick over 8 yearsUsing v23.1 lib, this did not work correctly, it always showed the accent color as bg, not the one defined, when trying to set it to the whole theme
-
Rémy DAVID over 8 yearsI confirm this does not work for the whole theme for API < 21, it works when assigning the theme to the button though
-
AhmedW over 8 yearsSame issue here on , on v23.1 the disabled button is the same colour as the enabled button. very frustrating. anyone figure this out?
-
AhmedW over 8 yearsThis approach worked for me , v23.1.1 code.google.com/p/android/issues/detail?id=176472
-
Apostrofix over 8 yearsbut the question is how to have material buttons with different colors, so that not all have the primary color of the theme.
-
Apostrofix over 8 yearsThis solution works fine, but the problem is when you need more buttons with different colors, then you have to create ripples and shapes for each button, which is quite annoying..
-
jturolla about 8 yearsThis is the simplest solution I think, this worked fine for android 4.2.2, 5.0 and others.
-
Sagar Nayak about 8 yearswhat are other attributes i can add into styles .
-
Semanticer about 8 yearsFrom AppCompatButton javadoc: "This will automatically be used when you use {@link android.widget.Button} in your * layouts. You should only need to manually use this class when writing custom views." So you dont have to manualy specify
<android.support.v7.widget.AppCompatButton />
just use<Button android:theme="@style/BrandButtonStyle"/>
-
Muhammad Alfaifi about 8 years@Semanticer thanks for noticing and you are right, old answer forgot to edit that :)
-
Micro about 8 yearsHow can you do this in Java?
-
Micro about 8 yearsYour Java code worked for me. And Muhammad Alfaifi answer helped set the text color of the button.
-
Micro about 8 yearsThis along with TouchBoarder's answer helped me set the button color and text color in Java using:
ViewCompat.setBackgroundTintList(your_colored_button, ContextCompat.getColorStateList(getContext(),R.color.your_custom_color));
-
ingyesid about 8 years@MicroR check the answer above.
-
wrozwad almost 8 yearsYou almost found the 100% correct way how to use new @style/Widget.AppCompat.Button.Colored ;) - see this answer stackoverflow.com/a/35811157/19733911
-
Prashanth Debbadwar almost 8 yearsI was using Activity instead of AppCompatActivity because of that button color didn't change.
-
vault over 7 yearsis there an easy way to programmatically set the tint (not background)?
-
sud007 over 7 yearsWonderful! Works on 4.4.4 as well! And selector state is also maintained quite well!
-
gMale over 7 yearsPer the docs: This is automatically used when setting buttons in your layouts. You only need to specify AppCompatButton when creating custom views.
-
velval over 7 yearsThis helped....I guess it is important to note to apply the button style as a theme instead of a style in the Button widget. I was applying it under style="@style/BlueImageButton" and it didn't work
-
Leon about 7 yearsInterestingly the XML changes worked perfectly in a fragment but not in an Activity layout. The Activity buttons used colorAccent only. The programmatic version worked though.
-
d.aemon almost 7 yearsAren't app compat widgets used automatically when inflating XML layouts? I believe
ImageView
gets replaced withAppCompatImageView
and it should be the same with all widgets, that have correspondingAppCompat
version. -
farukcankaya over 6 yearsNope, If you don't target last target version, you need to define
android.support.v7.widget.AppCompatImageView
explicitly. -
d.aemon over 6 yearsWhat do you mean by
last target version
, @power? -
Someone Somewhere over 6 years
Error:(3732, 21) No resource found that matches the given name: attr 'textColor'.
... the subtle difference in the values/style and values-v21/style shows you what we're up against in the Android world. -
Someone Somewhere over 6 yearsusing this method I see the lifting (shadow) effect, but not the ripple ...
-
epic over 3 yearsIf anyone looking for proof android are crazy, here it is! 3 hours and counting to change button color! Jesus Christ!