Ответ 1
d = DrawableCompat.wrap(d);
создает новый экземпляр, если он еще не был DrawableWrapper
, поэтому вы нажимаете этот новый экземпляр, но оригинал, который хранится в кнопке, остается тем же.
Весь код будет выглядеть примерно так:
Button b = (Button) findViewById(R.id.button);
Drawable d = b.getBackground();
d = DrawableCompat.wrap(d);
DrawableCompat.setTintList(d, getResources().getColorStateList(...));
b.setBackground(d); // or setBackgroundDrawable on older platforms
Итак, я бы пошел со вторым подходом, который вы описали, потому что он абстрагирует тяжелую работу от вас.
EDIT:
Просто погрузился в код appcompat и обнаружил, что AppCompatButton
tints iself, а не drawable, в отличие от Lollipop native (но только если фон включен в белый список, например, по умолчанию appcompat button drawable). Поэтому сначала нужно очистить оттенок от самой кнопки.
Button b = (Button) findViewById(R.id.button);
if (b instanceof AppCompatButton) {
((AppCompatButton)b).setSupportBackgroundTintList(null);
}
Drawable d = b.getBackground();
d = DrawableCompat.wrap(d);
DrawableCompat.setTintList(d, getResources().getColorStateList(...));
b.setBackground(d); // or setBackgroundDrawable on older platforms
ИЗМЕНИТЬ 2:
Приведенный выше код будет бросать NullPointerException
при попытке reset списка оттенков кнопок. В настоящее время я регистрирую отчет об ошибке.
Тем временем я предлагаю вам надуть кнопку с настраиваемым фоном (без белого списка для тонирования с помощью appcompat) напрямую или с фоном @null
и разрешением фона кнопки по умолчанию на
TypedArray ta = context.obtainStyledAttributes(null, new int[]{android.R.attr.background}, R.attr.buttonStyle, R.style.Widget_AppCompat_Button);
Drawable d = ta.getDrawable(0);
ta.recycle();
Окончательное решение
Так как все это выглядит довольно уродливо, самым простым (и только работающим, и надежным, но все же, как все-таки) решением для вас является следующее:
Button b = (Button) findViewById(R.id.button);
ColorStateList c = getResources().getColorStateList(...);
Drawable d = b.getBackground();
if (b instanceof AppCompatButton) {
// appcompat button replaces tint of its drawable background
((AppCompatButton)b).setSupportBackgroundTintList(c);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Lollipop button replaces tint of its drawable background
// however it is not equal to d.setTintList(c)
b.setBackgroundTintList(c);
} else {
// this should only happen if
// * manually creating a Button instead of AppCompatButton
// * LayoutInflater did not translate a Button to AppCompatButton
d = DrawableCompat.wrap(d);
DrawableCompat.setTintList(d, c);
b.setBackgroundDrawable(d);
}
Вы должны поместить это чудовище в класс утилиты.