Decided to try the new DrawableCompat
class. Following instructions from a reliable source, I'm calling:
Button b = (Button) findViewById(R.id.button);
Drawable d = b.getBackground();
d = DrawableCompat.wrap(d);
DrawableCompat.setTintList(d, getResources().getColorStateList(...));
Surprisingly, this does not work: my button background gets the color I define for the un-pressed, un-focused state, but it doesn't change on press / on focus.
I was able to succeed in a totally different way,
Button b = (Button) findViewById(R.id.button);
AppCompatButton b2 = (AppCompatButton) b; //direct casting to AppCompatButton throws annoying warning
b2.setSupportBackgroundTintList(getResources().getColorStateList(...));
which works and is even more compact, but however I wanted to use DrawableCompat
instead. Could you tell me why is it?
d = DrawableCompat.wrap(d);
creates a new instance if it's not alreadyDrawableWrapper
so you tint this new instance but the original which is stored in the button remains the same.The whole code would look something like this
So yeah, I'd go with the second approach you described because it abstracts the hard work from you.EDIT:
Just took a dive into appcompat code and found out that the
AppCompatButton
tints iself and not the drawable unlike Lollipop native (but only if the background is on the whitelist, e.g. default appcompat button drawable). So you have to clear tint from the button itself first.EDIT 2:
The above code will throw a
NullPointerException
when you try to reset the button's tint list. I'm currently filing a bug report.In the meantime I suggest you inflate the button with a custom background (non-whitelisted for tinting by appcompat) directly or with
@null
background and resolving the default button background byFinal solution
So as all this looks pretty fugly, the easiest (and only working and foolproof, yet hidious as well) solution for you now is this:
You should put this monstrosity away in a utility class.