Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 893
BoD Avatar asked Jan 02 '15 00:01

BoD


5 Answers

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').

like image 159
Snild Dolkow Avatar answered Nov 20 '22 04:11

Snild Dolkow


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>
like image 30
BoD Avatar answered Nov 20 '22 05:11

BoD


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.

like image 22
GUG Avatar answered Nov 20 '22 04:11

GUG


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.

like image 22
Carlos Borau Avatar answered Nov 20 '22 03:11

Carlos Borau


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.

enter image description here

In my project I used it, it worked.

like image 20
drakeet Avatar answered Nov 20 '22 05:11

drakeet