我正在尝试制作一个通用框架功能,当按下/聚焦/选择/等时,任何Drawable都会突出显示。
我的函数使用Drawable并返回StateListDrawable,其中默认状态是Drawable本身,而android.R.attr.state_pressed
的状态是相同的drawable,只需使用setColorFilter
应用过滤器。
我的问题是我无法克隆drawable并使用过滤器创建一个单独的实例。这是我想要实现的目标:
StateListDrawable makeHighlightable(Drawable drawable)
{
StateListDrawable res = new StateListDrawable();
Drawable clone = drawable.clone(); // how do I do this??
clone.setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);
res.addState(new int[] {android.R.attr.state_pressed}, clone);
res.addState(new int[] { }, drawable);
return res;
}
如果我没有克隆,那么过滤器显然适用于这两种状态。我试过玩mutate()
,但它没有帮助..
有什么想法吗?
更新
接受的答案确实克隆了一个可绘制的答案。这对我没有帮助,因为我的一般功能在一个不同的问题上失败了。似乎当你向StateList添加一个drawable时,它会丢失所有的过滤器。
答案 0 :(得分:153)
尝试以下方法:
Drawable clone = drawable.getConstantState().newDrawable();
答案 1 :(得分:96)
如果将过滤器/ etc应用于使用getConstantState().newDrawable()
创建的drawable,那么该drawable的所有实例也将被更改,因为drawable使用constantState
作为缓存!
因此,如果您使用滤镜和newDrawable()
为圆圈着色,则会更改所有圆圈的颜色。
如果你想在不影响其他实例的情况下使这个可绘制的可更新,那么你必须改变现有的常量状态。
// To make a drawable use a separate constant state
drawable.mutate()
有一个很好的解释,请参阅:
http://www.curious-creature.org/2009/05/02/drawable-mutations/
http://developer.android.com/reference/android/graphics/drawable/Drawable.html#mutate()
答案 2 :(得分:13)
这对我有用。
Drawable clone = drawable.getConstantState().newDrawable().mutate();
答案 3 :(得分:10)
这是我的解决方案,基于此SO question。
这个想法是ImageView
在用户触摸时获取滤色器,并在用户停止触摸时删除滤色器。内存中只有1个可绘制/位图,因此无需浪费它。它可以正常工作。
class PressedEffectStateListDrawable extends StateListDrawable {
private int selectionColor;
public PressedEffectStateListDrawable(Drawable drawable, int selectionColor) {
super();
this.selectionColor = selectionColor;
addState(new int[] { android.R.attr.state_pressed }, drawable);
addState(new int[] {}, drawable);
}
@Override
protected boolean onStateChange(int[] states) {
boolean isStatePressedInArray = false;
for (int state : states) {
if (state == android.R.attr.state_pressed) {
isStatePressedInArray = true;
}
}
if (isStatePressedInArray) {
super.setColorFilter(selectionColor, PorterDuff.Mode.MULTIPLY);
} else {
super.clearColorFilter();
}
return super.onStateChange(states);
}
@Override
public boolean isStateful() {
return true;
}
}
用法:
Drawable drawable = new FastBitmapDrawable(bm);
imageView.setImageDrawable(new PressedEffectStateListDrawable(drawable, 0xFF33b5e5));
答案 4 :(得分:1)
我回答了相关问题here
基本上看起来StateListDrawables确实失去了他们的过滤器。我从最初想要使用的Bitmap的修改副本创建了一个新的BitmapDrawale。
答案 5 :(得分:0)
Drawable clone = drawable.mutate().getConstantState().newDrawable().mutate();
如果getConstantState()
返回null
。
答案 6 :(得分:0)
使用newDrawable()
获取可绘制的克隆,但是请确保它是可变的,否则您的克隆效果就消失了,我使用了以下几行代码,它可以按预期运行。 getConstantState()
可能为注释建议的null,因此在克隆drawable时请处理此RunTimeException。
Drawable.ConstantState state = d.mutate().getConstantState();
if (state != null) {
Drawable drawable = state.newDrawable().mutate();
}