J'essaie de faire une fonction de cadre général qui rend tout Drawable mis en évidence lorsque pressé/concentré/sélectionné/etc.
Ma fonction prend un Drawable et retourne un StateListDrawable, où l'état par défaut est le Drawable lui-même, et l'état pour Android.R.attr.state_pressed
Est le même drawable, juste avec un filtre appliqué en utilisant setColorFilter
.
Mon problème est que je ne peux pas cloner le dessinable et en faire une instance séparée avec le filtre appliqué. Voici ce que j'essaie de réaliser:
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;
}
Si je ne clone pas, le filtre est évidemment appliqué aux deux états. J'ai essayé de jouer avec mutate()
mais ça n'aide pas ..
Des idées?
Mise à jour:
La réponse acceptée clone en effet un dessinable. Cela ne m'a pas aidé car ma fonction générale échoue sur un problème différent. Il semble que lorsque vous ajoutez un dessinable à une StateList, il perd tous ses filtres.
Essayez ce qui suit:
Drawable clone = drawable.getConstantState().newDrawable();
Si vous appliquez un filtre/etc à un dessinable créé avec getConstantState().newDrawable()
alors toutes les instances de ce dessinable seront également modifiées, car les dessinables utilisent le constantState
comme cache!
Donc, si vous coloriez un cercle à l'aide d'un filtre de couleur et d'une newDrawable()
, vous changerez la couleur de tous les cercles.
Si vous souhaitez rendre cette mise à jour dessinable sans affecter les autres instances, vous devez alors muter cet état constant existant.
// To make a drawable use a separate constant state
drawable.mutate()
Pour une bonne explication, voir:
http://www.curious-creature.org/2009/05/02/drawable-mutations/
http://developer.Android.com/reference/Android/graphics/drawable/Drawable.html#mutate ()
C'est ce qui fonctionne pour moi.
Drawable clone = drawable.getConstantState().newDrawable().mutate();
Ceci est ma solution, basée sur cela question SO .
L'idée est que ImageView
obtient un filtre de couleur lorsque l'utilisateur le touche et que le filtre de couleur est supprimé lorsque l'utilisateur cesse de le toucher. Un seul bitmap/bitmap est en mémoire, donc pas besoin de le gaspiller. Cela fonctionne comme il se doit.
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;
}
}
usage:
Drawable drawable = new FastBitmapDrawable(bm);
imageView.setImageDrawable(new PressedEffectStateListDrawable(drawable, 0xFF33b5e5));
J'ai répondu à une question connexe ici
Fondamentalement, il semble que StateListDrawables perd en effet ses filtres. J'ai créé un nouveau BitmapDrawale à partir d'une copie modifiée du Bitmap que je voulais utiliser à l'origine.