Использование класса DrawableCompat для применения tintList
Решил попробовать новый DrawableCompat
учебный класс. Следуя инструкциям из надежного источника, я звоню:
Button b = (Button) findViewById(R.id.button);
Drawable d = b.getBackground();
d = DrawableCompat.wrap(d);
DrawableCompat.setTintList(d, getResources().getColorStateList(...));
Удивительно, но это не работает: фон моей кнопки получает цвет, который я определяю для не нажатого, не сфокусированного состояния, но он не меняется при нажатии / на фокусе.
Я смог добиться успеха совершенно по-другому,
Button b = (Button) findViewById(R.id.button);
AppCompatButton b2 = (AppCompatButton) b; //direct casting to AppCompatButton throws annoying warning
b2.setSupportBackgroundTintList(getResources().getColorStateList(...));
который работает и еще более компактен, но я хотел использовать DrawableCompat
вместо. Не могли бы вы сказать мне, почему это?
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
Так что да, я бы выбрал второй подход, который вы описали, потому что он отвлекает вас от тяжелой работы.
РЕДАКТИРОВАТЬ:
Просто погрузился в код appcompat и обнаружил, что AppCompatButton
в отличие от нативного Lollipop, окрашивает себя, а не рисуемое (но только если фон находится в белом списке, например, кнопка appcompat по умолчанию рисуется). Таким образом, вы должны очистить оттенок от самой кнопки в первую очередь.
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
при попытке сбросить список оттенков кнопки. В настоящее время я подаю отчет об ошибке.
В то же время, я предлагаю вам надуть кнопку с помощью собственного фона (не белого для тонирования 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);
}
Вы должны убрать это чудовище в служебный класс.