web-dev-qa-db-fra.com

Android: Teinte utilisant DrawableCompat

J'essaie de teinter une image avant Android API niveau 21. J'ai réussi à teinter des éléments en utilisant:

<Android:tint="@color/red"/>

Cependant, je n'arrive pas à comprendre comment le faire via du code sur une ImageView:

Drawable iconDrawable = this.mContext.getResources().getDrawable(R.drawable.somedrawable);
DrawableCompat.setTint(iconDrawable, this.mContext.getResources().getColor(R.color.red));
imageView.setImageDrawable(iconDrawable);

J'ai essayé de régler le TintMode mais cela ne semble pas faire de différence. Suis-je en train d'utiliser incorrectement la classe de compatibilité v4 DrawableCompat?

48
Hippopatimus

La façon la plus simple de teinter multiplateforme (si vous n'avez pas besoin d'un ColorStateList) est:

drawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);

N'oubliez pas de muter le Drawable avant d'appliquer le filtre.

43
BladeCoder

Dans le cas où quelqu'un a besoin d'utiliser la teinture de DrawableCompat sans affecter les autres tirables, voici comment vous le faites avec mutate():

Drawable drawable = getResources().getDrawable(R.drawable.some_drawable);
Drawable wrappedDrawable = DrawableCompat.wrap(drawable);
wrappedDrawable = wrappedDrawable.mutate();
DrawableCompat.setTint(wrappedDrawable, getResources().getColor(R.color.white));

Qui peut être simplifié pour:

Drawable drawable = getResources().getDrawable(R.drawable.some_drawable);
drawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(drawable.mutate(), getResources().getColor(R.color.white));
120
Renan Ferrari

Auparavant, la teinture n'était pas prise en charge par DrawableCompat. À partir de la bibliothèque de support 22.1, vous pouvez le faire, mais vous devez le faire de cette manière:

Drawable normalDrawable = getResources().getDrawable(R.drawable.drawable_to_tint);
Drawable wrapDrawable = DrawableCompat.wrap(normalDrawable);
DrawableCompat.setTint(wrapDrawable, getResources().getColor(R.color.colorPrimaryLight));
53
Simon K. Gerges

Les réponses ici ne fonctionnent pas pour les appareils pré-Lollipop (SupportLib 23.4.0) mais j'ai posté une solution de contournement qui fonctionne pour l'API 17 et plus: https://stackoverflow.com/a/37434219/ 2170109

Le code suivant a été testé et fonctionne sur les API 17, 19, 21, 22, 23 et N Preview 3:

    // https://stackoverflow.com/a/30928051/2170109
    Drawable drawable = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.vector));
    image.setImageDrawable(drawable);

    /*
     * need to use the filter | https://stackoverflow.com/a/30880522/2170109
     * (even if compat should use it for pre-API21-devices | https://stackoverflow.com/a/27812472/2170109)
     */
    int color = ContextCompat.getColor(context, R.color.yourcolor);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {
        DrawableCompat.setTint(drawable, color);

    } else {
        drawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
    }
29
hardysim

Si vous regardez le code source de DrawableCompat, vous verrez que pour toute version <21 la méthode ne fait rien .

L'idée de DrawableCompat semble simplement ne pas planter sur les anciennes versions, plutôt que de fournir réellement cette fonctionnalité.

6
Michael Smith

Avec la bibliothèque de support 22.1, vous pouvez utiliser DrawableCompat pour teinter les tirages.

DrawableCompat.wrap (Drawable) et setTint (), setTintList () et setTintMode () fonctionneront juste: pas besoin de créer et de maintenir des drawables séparés uniquement pour prendre en charge plusieurs couleurs!

3
bugraoral

Je vais partager ma solution ici car cela peut faire gagner du temps à quelqu'un.

J'avais un ImageView avec vector drawable utilisé comme source drawable (en fait, c'était Support Vector Drawable from Android Support Library 23.3). Donc, d'abord je l'ai enveloppé comme ça:

mImageView.setImageDrawable(DrawableCompat.wrap(mImageView.getDrawable()));

Et après cela, j'ai essayé d'appliquer une teinte comme ceci:

DrawableCompat.setTint(
    mImageView.getDrawable(),
    getResources().getColor(R.color.main_color)
);

Pas de chance.

J'ai essayé d'appeler mutate() sur le drawable enveloppé, ainsi que sur le drawable original - toujours pas de chance. invalidate() appelé mImageView a fait l'affaire.

2
aga