使用 DrawableCompat class 应用 tintList
Using DrawableCompat class to apply a tintList
决定尝试新的 DrawableCompat
class。按照 reliable source 的指示,我打电话给:
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
。你能告诉我这是为什么吗?
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
着色 iself 而不是像 Lollipop native 那样的可绘制对象(但前提是背景位于白名单,例如默认的 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);
}
你应该把这个怪物放在实用程序中 class。
决定尝试新的 DrawableCompat
class。按照 reliable source 的指示,我打电话给:
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
。你能告诉我这是为什么吗?
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
着色 iself 而不是像 Lollipop native 那样的可绘制对象(但前提是背景位于白名单,例如默认的 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);
}
你应该把这个怪物放在实用程序中 class。