使用DrawableCompat类应用tintList

时间:2015-05-16 13:04:38

标签: android android-support-library appcompat-v7-r22.1

决定尝试新的DrawableCompat课程。按照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。你能告诉我为什么会这样吗?

1 个答案:

答案 0 :(得分:4)

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 tints iself 而不是Lollipop本机不可绘制(但前提是背景位于白名单上,例如默认appcompat按钮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。我目前正在提交错误报告。

与此同时,我建议您直接或使用@null背景以及通过

解析默认按钮背景,使用自定义背景(非白名单以便通过appcompat进行着色)来膨胀按钮
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);
}

你应该把这个怪物放在一个实用程序类中。