Android: клонирование отрисовки для создания StateListDrawable с фильтрами
Я пытаюсь сделать общую каркасную функцию, которая делает любой Drawable выделенным при нажатии / фокусировке / выделении / и т.д.
Моя функция берет Drawable и возвращает StateListDrawable, где состоянием по умолчанию является сам Drawable, а состояние для android.R.attr.state_pressed
то же самое рисовать, только с фильтром, примененным с помощью setColorFilter
,
Моя проблема в том, что я не могу клонировать нарисованное и создать отдельный экземпляр с примененным фильтром. Вот что я пытаюсь достичь:
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()
но это не помогает..
Есть идеи?
Обновить:
Принятый ответ действительно клонирует притягивающий. Это не помогло мне, хотя, потому что моя общая функция не работает из-за другой проблемы. Кажется, что когда вы добавляете drawable в StateList, он теряет все свои фильтры.
5 ответов
Попробуйте следующее:
Drawable clone = drawable.getConstantState().newDrawable();
Если вы примените фильтр / etc к рисованному объекту, созданному с getConstantState().newDrawable()
тогда все экземпляры этого drawable будут также изменены, так как drawables используют 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
Это то, что работает для меня.
Drawable clone = drawable.getConstantState().newDrawable().mutate();
Это мое решение, основанное на этом вопросе.
Идея в том, что 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));
Я ответил на связанный вопрос здесь
По сути, кажется, что StateListDrawables действительно теряют свои фильтры. Я создал новый BitmapDrawale из измененной копии растрового изображения, которое изначально хотел использовать.
Получите возможность клонирования с помощью newDrawable()
но убедитесь, что он изменяемый, иначе эффект клонирования исчезнет, я использовал эти несколько строк кода, и он работает должным образом. getConstantState()
может иметь значение null, как это предлагается аннотацией, поэтому обработайте это RunTimeException при клонировании drawable.
Drawable.ConstantState state = d.mutate().getConstantState();
if (state != null) {
Drawable drawable = state.newDrawable().mutate();
}
Drawable clone = drawable.mutate().getConstantState().newDrawable().mutate();
в случае getConstantState()
возвращается null
.