Cambia il colore di riempimento sull'asset vettoriale in Android Studio


169

Android Studio ora supporta risorse vettoriali su 21+ e genererà png per versioni inferiori in fase di compilazione. Ho una risorsa vettoriale (dalle icone dei materiali) che voglio cambiare il colore di riempimento. Funziona su 21+, ma i png generati non cambiano colore. C'è un modo per fare questo?

<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"/>

Risposte:


333

Non modificare direttamente le risorse vettoriali. Se stai usando un disegno vettoriale in un ImageButton, scegli semplicemente il tuo colore 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" />

24
tinting funziona solo su 21+ dispositivi, hai qualche suggerimento per i dispositivi pre-lecca-lecca
mudit

12
android: tint funziona su tutte le versioni di Android dall'APIv1. Quello che vuoi dire è drawableTint.
AAAA-MM-GG

31
android:tintdeve essere dopoandroid:src
EmmanuelMess

5
Che dire di drawableLeftin Button?
Pratik Butani,

8
@mudit prova a usare un vettore con fillColor = "# colorvalue", non usare un riferimento @ color perché funzionano solo con SDK 21+ per i vettori (quindi non per i PNG generati)
PieterAelse

95

Puoi farlo.

MA non puoi usare i riferimenti @color per i colori (..lame), altrimenti funzionerà solo per 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"/>


11
Questa dovrebbe essere la risposta accettata! I riferimenti @color non funzionano nei vettori pre-Lollipop (quindi vettoriali -> conversione PNG) code.google.com/p/android/issues/detail?id=186431
PieterAelse

5
I riferimenti @color ora possono essere utilizzati per l'attributo fillColor per tutte le versioni di Android, tuttavia non supporta gli elenchi degli stati dei colori.
TheIT

Sembra che il modo di fare elenchi di stati vettoriali sia con AnimatedStateListDrawable s
gMale

1
@TheIT cosa devo abilitarlo? Non sembra funzionare per me
urSus il

@PieterAelse Non sono sicuro, cosa succede se si desidera utilizzare la stessa risorsa ma con sfondi diversi (tinte come nella risposta precedente). Nella tua soluzione avrai diversi casi di stessa risorsa ma con colore di riempimento diverso
Anton Makov,

71

Come detto in altre risposte, non modificare direttamente il disegno vettoriale, ma puoi tingere in codice java, in questo modo:

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

E per semplicità, ho creato una classe di supporto:

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;
    }
}

Per usare basta fare quanto segue:

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

O:

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

    actionBar.setHomeAsUpIndicator(drawable);

Ciao Filipe, grazie per la tua risposta. Hai una libreria, github di codice snipped in cui possiamo vedere la licenza? grazie :)
Vincent D.

2
No Vicent, nessuna licenza. La soluzione è così semplice che immagino che il modello Builder usato qui non sia necessario. Ma chiunque può beneficiare di questa soluzione e utilizzare senza licenza.
Filipe Bezerra de Sousa,

Bella risposta! Funziona esattamente come mi serve
Eoin

1
@VincentD. Il piè di pagina della SO dice "contributi degli utenti concessi in licenza in cc by-sa 3.0 con attribuzione obbligatoria"
shelll

Ha funzionato per me con alcune modifiche. Grazie per l'aiuto.
André Luiz Reis,

36

Per cambiare il colore dell'immagine vettoriale puoi usare direttamente 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" />

Per cambiare colore in modo programmatico

ImageView ivVectorImage = (ImageView) findViewById(R.id.ivVectorImage);
ivVectorImage.setColorFilter(getResources().getColor(R.color.colorPrimary));

getColor () è obsoleto
David,

Come usarlo per il disegno di TextView ***?
Hemant Kaushik il

getColor (ResId) è obsoleto @David, ma getColor(ResId, Theme)non lo è. Oppure puoi usare ResourcesCompat.getColor(getResources(), R.color.primary, null);se non ti interessa il tema ... o se il tuo delegato di contesto / politica È un'attività, puoi farlo getTheme()per l'ultimo parametro.
Martin Marconcini,

15

Attualmente l'assunzione di lavoro è Android: fillColor = "# FFFFFF"

Niente ha funzionato per me tranne la dura codifica nel vettore

<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"/>

Tuttavia, fillcolor e tint potrebbero funzionare presto. Si prega di consultare questa discussione per ulteriori informazioni:

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

Anche i colori potrebbero rimanere nella cache, quindi potrebbe essere utile eliminare l'app per tutti gli utenti.


7

Android Studio ora supporta i vettori pre-lecca-lecca. Nessuna conversione PNG. Puoi ancora cambiare il colore di riempimento e funzionerà.

In ImageView, utilizzare

 app:srcCompat="@drawable/ic_more_vert_24dp"

Nel tuo file gradle,

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

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

10
La domanda è "come cambiare il colore di riempimento vettoriale", non "come utilizzare l'asset vettoriale"
Leo Droidcoder

5

Aggiornamento: AppCompatsupporto

Altre risposte che sospettano se android:tintfunzioneranno solo su 21+ dispositivi, AppCompat ( v23.2.0 e versioni successive ) ora fornisce una gestione retrocompatibile dell'attributo tint.

Quindi, il corso dell'azione sarebbe usare AppCompatImageViewe app:srcCompat(nello spazio dei nomi AppCompat) invece di android:src(spazio dei nomi Android).

Ecco un esempio (AndroidX: questo è 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" />

E non dimenticare di abilitare il supporto per il disegno vettoriale in gradle:

vectorDrawables.useSupportLibrary = true 

Solo un aggiornamento. Oggi AppCompatImageViewè sottoandroidx.appcompat.widget.AppCompatImageView
Roc Boronat il

2

Aggiungi questa libreria al Gradle per abilitare il disegno vettoriale a colori nei vecchi dispositivi Android.

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

e sincronizzare nuovamente il livello. Penso che risolverà il problema.


2

Se i vettori non mostrano i colori impostati individualmente usando fillColor, potrebbero essere impostati su un parametro widget predefinito.

Prova ad aggiungere app:itemIconTint="@color/lime"a activity_main.xml per impostare un tipo di colore predefinito per le icone del 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 @ developers.android


In Android Studio 3.6 modifica in svg xml questo campo: android: fillColor = "# FFFFC400"
a_subscriber

1

se cerchi di supportare la vecchia versione pre lolipop

usa lo stesso codice xml con alcune modifiche

invece del normale ImageView --> AppCompatImageView

invece di android:src --> app:srcCompat

ecco un esempio

<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" />

Non dimenticate aggiornare il Gradle come @ Sayooj Valsan menzione

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

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

Avviso A nessuno usa il vettore mai e poi mai dare il tuo riferimento vettoriale al colore come questo android:fillColor="@color/primary"dare il suo valore esadecimale.


perché mai usare @colorper fillcolor?
HoseinIT,

0

Per coloro che non usano un ImageView, il seguente ha funzionato per me su un piano View(e quindi il comportamento dovrebbe replicarsi su qualsiasi tipo di vista)

<View
    android:background="@drawable/ic_reset"
    android:backgroundTint="@color/colorLightText" />
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.