Lollipop's backgroundTint has no effect on a Button
I have a Button in my Activity, and I'd like it to have my theme's accent color.
Instead of making my own drawables like we had to do pre-Lollipop, naturally I'd like to use the new backgroundTint
attribute.
<Button
android:id="@+id/btnAddCode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/accent"
android:text="@string/addressInfo_edit_addCode" />
Unfortunately it has no effect, the button stays gray.
I tried different values for backgroundTintMode
, which didn't change anything.
I also tried doing it programmatically in my Activity, which didn't change anything.
addCodeView.findViewById(R.id.btnAddCode).setBackgroundTintList(
getResources().getColorStateList(R.color.accent));
Why is my tint ignored?
EDIT: Just to clarify, I am indeed testing on a Lollipop device. Other widgets (e.g. EditText) are correctly and automatically tinted.
The bad news
Like BoD says, it's meaningless to tint a Button's background in Lollipop 5.0 (API level 21).
The good news
Lollipop 5.1 (API level 22) seems to have fixed this by changing btn_mtrl_default_shape.xml (among other files): https://android.googlesource.com/platform/frameworks/base/+/6dfa60f33ca6018959ebff1efde82db7d2aed1e3%5E!/#F0
The great news
The new support library (version 22.1+) adds backward-compatible tinting support to lots of components, including AppCompatButton!
Unfortunately, the android:backgroundTint
property still doesn't work (maybe I'm doing something wrong) -- so you have to set the ColorStateList
in code, using setSupportBackgroundTintList()
. It'd be really nice to see android:backgroundTint
supported in the future. Update: Marcio Granzotto commented that app:backgroundTint
works on AppCompatButton! Note that it's app:
, not android:
, because it's in the app/library.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<AppCompatButton
android:id="@+id/mybutton"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="Testing, testing"
app:backgroundTint="#ff00ff"/>
</LinearLayout>
Your activity will automatically inflate an AppCompatButton
instead of the normal Button
if you let it inherit from AppCompatActivity
.
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppCompatButton v = (AppCompatButton) findViewById(R.id.mybutton);
ColorStateList csl = new ColorStateList(new int[][]{new int[0]}, new int[]{0xffffcc00});
v.setSupportBackgroundTintList(csl);
}
}
You should of course get the ColorStateList
from a color resource, but I was lazy, so...
Oh, and don't forget to base your app theme on one of the Theme.AppCompat
themes, or the compat views will be very, very sad... ;)
This worked on both 2.3.7 (Gingerbread MR1) and 5.0 (Lollipop 'Classic').
It seems that tinting a ripple drawable is meaningless (and the default background of a button is a ripple drawable).
In fact, after looking at the platform's default button drawable, I found the "correct" way to do this:. You have to define this in your theme:
<item name="android:colorButtonNormal">@color/accent</item>
(Of course this is only for level 21+.)
Warning: since this is defined in a theme, this will use the given color for all the buttons (at least all of the buttons in activities using that theme.)
As a bonus, you can also change the ripple color by defining this:
<item name="android:colorControlHighlight">@color/accent_ripple</item>
To resolve issues related to tinting on Android 5.0.x I use something like this:
public static void setButtonTint(Button button, ColorStateList tint) {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP && button instanceof AppCompatButton) {
((AppCompatButton) button).setSupportBackgroundTintList(tint);
} else {
ViewCompat.setBackgroundTintList(button, tint);
}
}
It uses the support method only for API 21 and the ViewCompat one for all other cases.
I usually do it dynamically by using PorterDuff:
mbutton = (Button) findViewById(R.id.mybutton);
mbutton.getBackground().setColorFilter(anycolor, PorterDuff.Mode.MULTIPLY);
You can check different blending modes here and nice examples here.
Just use app:backgroundTint
instead of android:backgroundTint
, the tint will take effect below Lollipop. The reason is AppCompatActivity
use AppCompatViewInflater
to auto change Button or TextView to AppCompatButton or AppCompatTextView, then app:backgroundTint
take effect.
In my project I used it, it worked.