Modifier la couleur de remplissage sur l'élément vectoriel dans Android Studio

169

Android Studio prend désormais en charge les ressources vectorielles sur 21+ et générera des png pour les versions inférieures au moment de la compilation. J'ai un élément vectoriel (à partir des icônes de matériau) dont je souhaite modifier la couleur de remplissage. Cela fonctionne sur 21+, mais les png générés ne changent pas de couleur. Y a-t-il un moyen de faire cela?

<vector android:height="48dp" android:viewportHeight="24.0"
android:viewportWidth="24.0" android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@color/primary" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>

Patrick
la source

Réponses:

333

Ne modifiez pas directement les ressources vectorielles. Si vous utilisez un vecteur dessinable dans un ImageButton, choisissez simplement votre couleur android:tint.

<ImageButton
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:id="@+id/button"
        android:src="@drawable/ic_more_vert_24dp"
        android:tint="@color/primary" />
AAAA-MM-JJ
la source
24
la teinture ne fonctionne que sur plus de 21 appareils, avez-vous des suggestions pour les appareils pré-sucette
mudit
12
android: la teinte fonctionne sur toutes les versions d'Android depuis APIv1. Ce que vous voulez dire, c'est drawableTint.
AAAA-MM-JJ
31
android:tintdoit être aprèsandroid:src
EmmanuelMess
5
Qu'en est- il drawableLeftdans Button?
Pratik Butani
8
@mudit essayez d'utiliser un vecteur avec fillColor = "# colorvalue", n'utilisez pas de référence @ color car ils ne fonctionnent que le SDK 21+ pour les vecteurs (donc pas pour les PNG générés)
PieterAelse
95

Tu peux le faire.

MAIS vous ne pouvez pas utiliser de références @color pour les couleurs (..lame), sinon cela ne fonctionnera que pour L +

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24.0"
    android:viewportHeight="24.0">
<path
    android:fillColor="#FFAABB"
    android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zm-6,0C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>

urSus
la source
11
Cela devrait être la réponse acceptée! Les références @color ne fonctionnent pas dans les vecteurs pré-Lollipop (donc vector -> conversion PNG) code.google.com/p/android/issues/detail?id=186431
PieterAelse
5
Les références @color peuvent désormais être utilisées pour l'attribut fillColor pour toutes les versions d'Android, mais il ne prend pas en charge les listes d'état de couleur.
TheIT
Il semble que la façon de faire des listes d'états vectoriels soit avec AnimatedStateListDrawable s
gMale
1
@TheIT que dois-je l'activer? Ne semble pas fonctionner pour moi
urSus
@PieterAelse Je ne suis pas sûr, que faire si vous souhaitez utiliser le même élément mais avec des arrière-plans différents (teintes comme dans la réponse précédente). Dans votre solution, vous aurez plusieurs instances de la même ressource mais avec une couleur de remplissage différente
Anton Makov
71

Comme dit dans d'autres réponses, n'éditez pas le vecteur dessiné directement, vous pouvez à la place teinter dans le code java, comme ça:

    mWrappedDrawable = mDrawable.mutate();
    mWrappedDrawable = DrawableCompat.wrap(mWrappedDrawable);
    DrawableCompat.setTint(mWrappedDrawable, mColor);
    DrawableCompat.setTintMode(mWrappedDrawable, PorterDuff.Mode.SRC_IN);

Et par souci de simplicité, j'ai créé une classe d'assistance:

import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;

/**
 * {@link Drawable} helper class.
 *
 * @author Filipe Bezerra
 * @version 18/01/2016
 * @since 18/01/2016
 */
public class DrawableHelper {
    @NonNull Context mContext;
    @ColorRes private int mColor;
    private Drawable mDrawable;
    private Drawable mWrappedDrawable;

    public DrawableHelper(@NonNull Context context) {
        mContext = context;
    }

    public static DrawableHelper withContext(@NonNull Context context) {
        return new DrawableHelper(context);
    }

    public DrawableHelper withDrawable(@DrawableRes int drawableRes) {
        mDrawable = ContextCompat.getDrawable(mContext, drawableRes);
        return this;
    }

    public DrawableHelper withDrawable(@NonNull Drawable drawable) {
        mDrawable = drawable;
        return this;
    }

    public DrawableHelper withColor(@ColorRes int colorRes) {
        mColor = ContextCompat.getColor(mContext, colorRes);
        return this;
    }

    public DrawableHelper tint() {
        if (mDrawable == null) {
            throw new NullPointerException("É preciso informar o recurso drawable pelo método withDrawable()");
        }

        if (mColor == 0) {
            throw new IllegalStateException("É necessário informar a cor a ser definida pelo método withColor()");
        }

        mWrappedDrawable = mDrawable.mutate();
        mWrappedDrawable = DrawableCompat.wrap(mWrappedDrawable);
        DrawableCompat.setTint(mWrappedDrawable, mColor);
        DrawableCompat.setTintMode(mWrappedDrawable, PorterDuff.Mode.SRC_IN);

        return this;
    }

    @SuppressWarnings("deprecation")
    public void applyToBackground(@NonNull View view) {
        if (mWrappedDrawable == null) {
            throw new NullPointerException("É preciso chamar o método tint()");
        }

        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            view.setBackground(mWrappedDrawable);
        } else {
            view.setBackgroundDrawable(mWrappedDrawable);
        }
    }

    public void applyTo(@NonNull ImageView imageView) {
        if (mWrappedDrawable == null) {
            throw new NullPointerException("É preciso chamar o método tint()");
        }

        imageView.setImageDrawable(mWrappedDrawable);
    }

    public void applyTo(@NonNull MenuItem menuItem) {
        if (mWrappedDrawable == null) {
            throw new NullPointerException("É preciso chamar o método tint()");
        }

        menuItem.setIcon(mWrappedDrawable);
    }

    public Drawable get() {
        if (mWrappedDrawable == null) {
            throw new NullPointerException("É preciso chamar o método tint()");
        }

        return mWrappedDrawable;
    }
}

Pour utiliser, procédez comme suit:

    DrawableHelper
            .withContext(this)
            .withColor(R.color.white)
            .withDrawable(R.drawable.ic_search_24dp)
            .tint()
            .applyTo(mSearchItem);

Ou:

    final Drawable drawable = DrawableHelper
            .withContext(this)
            .withColor(R.color.white)
            .withDrawable(R.drawable.ic_search_24dp)
            .tint()
            .get();

    actionBar.setHomeAsUpIndicator(drawable);
Filipe Bezerra de Sousa
la source
Salut Filipe, merci pour votre réponse. Avez-vous une bibliothèque, du code extrait github où nous pouvons voir la licence? merci :)
Vincent D.
2
Non Vicent, pas de licence du tout. La solution est si simple que je suppose que le modèle Builder utilisé ici n'est pas nécessaire. Mais tout le monde peut bénéficier de cette solution et l'utiliser sans licence.
Filipe Bezerra de Sousa
Très bonne réponse! Fonctionne exactement comme j'ai besoin
Eoin
1
@VincentD. Le pied de page de la page Web SO indique "Contributions des utilisateurs sous licence cc by-sa 3.0 avec attribution requise"
shelll
Cela a fonctionné pour moi avec quelques changements. Merci de votre aide.
André Luiz Reis
36

Pour changer la couleur de l'image vectorielle, vous pouvez utiliser directement android: tint = "@ color / colorAccent"

<ImageView
        android:id="@+id/ivVectorImage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_account_circle_black_24dp"
        android:tint="@color/colorAccent" />

Pour changer de couleur par programme

ImageView ivVectorImage = (ImageView) findViewById(R.id.ivVectorImage);
ivVectorImage.setColorFilter(getResources().getColor(R.color.colorPrimary));
Rana Ranvijay Singh
la source
getColor () est obsolète
David
Comment l'utiliser pour le dessinable *** de TextView?
Hemant Kaushik
getColor (ResId) est obsolète @David, mais getColor(ResId, Theme)ne l'est pas. Ou vous pouvez utiliser ResourcesCompat.getColor(getResources(), R.color.primary, null);si vous ne vous souciez pas du thème… ou si votre délégué de contexte / politique EST une activité, vous pouvez le faire getTheme()pour ce dernier paramètre.
Martin Marconcini
15

Actuellement, la solution de travail est android: fillColor = "# FFFFFF"

Rien n'a fonctionné pour moi sauf le codage en dur dans le vecteur

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24.0"
      android:fillColor="#FFFFFF"
    android:viewportHeight="24.0">
<path
    android:fillColor="#FFFFFF"
    android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zm-6,0C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>

Cependant, la couleur de remplissage et la teinte pourraient bientôt fonctionner. Veuillez consulter cette discussion pour plus d'informations:

https://code.google.com/p/android/issues/detail?id=186431

Les couleurs peuvent également rester dans le cache, donc la suppression de l'application pour tous les utilisateurs peut aider.

sivi
la source
7

Le studio Android prend désormais en charge les vecteurs pré-sucette. Pas de conversion PNG. Vous pouvez toujours changer votre couleur de remplissage et cela fonctionnera.

Dans votre ImageView, utilisez

 app:srcCompat="@drawable/ic_more_vert_24dp"

Dans votre fichier gradle,

 // Gradle Plugin 2.0+  
 android {  
   defaultConfig {  
     vectorDrawables.useSupportLibrary = true  
   }  
 }  

 compile 'com.android.support:design:23.4.0'
Sayooj Valsan
la source
10
La question est "comment changer la couleur de remplissage du vecteur", pas "comment utiliser l'élément vectoriel"
Leo Droidcoder
5

Mise à jour: AppCompatsupport

D'autres réponses soupçonnant si android:tintcela fonctionnera uniquement sur 21+ appareils uniquement, AppCompat ( v23.2.0 et supérieur ) fournit désormais une gestion rétrocompatible de l'attribut de teinte.

Ainsi, la marche à suivre serait d'utiliser AppCompatImageViewet app:srcCompat(dans l'espace de noms AppCompat) au lieu de android:src(espace de noms Android).

Voici un exemple (AndroidX: il s'agit de androidx.appcompat.widget.AppCompatImageView ;)):

<android.support.v7.widget.AppCompatImageView
        android:id="@+id/credits_material_icon"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="16dp"
        android:layout_marginStart="16dp"
        android:scaleType="fitCenter"
        android:tint="#ffd2ee"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:srcCompat="@drawable/ic_dollar_coin_stack" />

Et n'oubliez pas d'activer la prise en charge des dessins vectoriels dans gradle:

vectorDrawables.useSupportLibrary = true 
Manish Kumar Sharma
la source
Juste une mise à jour. Aujourd'hui, AppCompatImageViewc'est sousandroidx.appcompat.widget.AppCompatImageView
Roc Boronat
2

Ajoutez cette bibliothèque au Gradle pour activer le dessin vectoriel de couleur dans les anciens appareils Android.

compile 'com.android.support:palette-v7:26.0.0-alpha1'

et resynchroniser gradle. Je pense que cela résoudra le problème.

Siddhartha Maji
la source
2

Si les vecteurs n'affichent pas les couleurs définies individuellement à l'aide de fillColor, ils peuvent être définis sur un paramètre de widget par défaut.

Essayez d'ajouter app:itemIconTint="@color/lime"à activity_main.xml pour définir un type de couleur par défaut pour les icônes de widget.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:itemIconTint="@color/lime"
        app:menu="@menu/activity_main_drawer" />

</android.support.v4.widget.DrawerLayout>

VectorDrawable @ développeurs.android

Lubi
la source
Dans Android Studio 3.6, changez en svg xml ce champ: android: fillColor = "# FFFFC400"
a_subscriber
1

si vous cherchez à prendre en charge l'ancienne version pré lolipop

utiliser le même code xml avec quelques modifications

au lieu de normal ImageView --> AppCompatImageView

au lieu de android:src --> app:srcCompat

voici un exemple

<android.support.v7.widget.AppCompatImageView
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:id="@+id/button"
        app:srcCompat="@drawable/ic_more_vert_24dp"
        android:tint="@color/primary" />

n'oubliez pas de mettre à jour votre note comme @ Sayooj Valsan mentionne

// Gradle Plugin 2.0+  
 android {  
   defaultConfig {  
     vectorDrawables.useSupportLibrary = true  
   }  
 }  

 compile 'com.android.support:design:23.4.0'

Remarque Pour quiconque utilise un vecteur, ne donnez jamais jamais à votre vecteur de référence à une couleur comme celle-ci android:fillColor="@color/primary"donne sa valeur hexadécimale.

Mina Fawzy
la source
pourquoi ne jamais utiliser @colorpour fillcolor?
HoseinIT
0

Pour ceux qui n'utilisent pas de ImageView, ce qui suit a fonctionné pour moi sur un simple View(et par conséquent, le comportement devrait se reproduire sur n'importe quel type de vue)

<View
    android:background="@drawable/ic_reset"
    android:backgroundTint="@color/colorLightText" />
Bonton255
la source