Alterar a cor de preenchimento no ativo de vetor no Android Studio


169

O Android Studio agora suporta recursos vetoriais com mais de 21 anos e gera pngs para versões inferiores em tempo de compilação. Eu tenho um ativo de vetor (dos Ícones dos materiais) que desejo alterar a cor do preenchimento. Isso funciona com mais de 21 anos, mas os pngs gerados não mudam de cor. Existe uma maneira de fazer isso?

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

Respostas:


333

Não edite os ativos de vetor diretamente. Se você estiver usando um desenho vetorial em um ImageButton, basta escolher sua cor 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
tingindo só funciona em dispositivos 21+, você tem alguma sugestão para dispositivos pré-pirulito
mudit

12
android: tint funciona em todas as versões do Android desde APIv1. O que você quer dizer é drawableTint.
AAAA-MM-DD

31
android:tintdeve ser depois deandroid:src
EmmanuelMess

5
Que tal drawableLeftem Button?
Pratik Butani 14/05

8
@mudit tente usar um vetor com fillColor = "# ColorValue", não use uma referência @ cor, porque eles só SDK trabalho 21+ para vetores (portanto, não para o PNG gerada)
PieterAelse

95

Você consegue.

MAS você não pode usar referências @color para cores (..lame), caso contrário, funcionará apenas para 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
Esta deve ser a resposta aceita! As referências @color não funcionam em vetores pré-pirulito (então vetor -> conversão PNG) code.google.com/p/android/issues/detail?id=186431
PieterAelse

5
As referências @color agora podem ser usadas para o atributo fillColor para todas as versões do Android, no entanto, ele não suporta listas de estados de cores.
TheIT 13/12

Parece que a maneira de fazer listas estaduais vetor é com AnimatedStateListDrawable s
gMale

1
@TheIT, o que tenho para habilitá-lo? Não parece trabalhar para mim
Ursus

@PieterAelse Não tenho certeza, e se você quiser usar o mesmo recurso, mas com fundos diferentes (tons como na resposta anterior). Na sua solução, você terá várias instâncias do mesmo recurso, mas com cores de preenchimento diferentes
Anton Makov 27/02

71

Como dito em outras respostas, não edite o vetor desenhável diretamente, você pode pintar o código java, assim:

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

E por uma questão de simplicidade, criei uma classe auxiliar:

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

Para usar, faça o seguinte:

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

Olá Filipe, obrigado pela sua resposta. Você tem uma biblioteca, com código sniper no github, onde podemos ver a licença? obrigada :) #
Vincent D.

2
Não Vicent, nenhuma licença. A solução é tão simples que acho que o padrão do Builder usado aqui não é necessário. Mas qualquer pessoa pode se beneficiar dessa solução e usá-la sem licença.
Filipe Bezerra de Sousa

Ótima resposta! Funciona exatamente como eu preciso
Eoin

1
@VincentD. O rodapé da página da Web do SO diz "contribuições do usuário licenciadas sob o cc by-sa 3.0 com atribuição necessária"
shelll

Funcionou para mim com algumas mudanças. Obrigado pela ajuda.
André Luiz Reis

36

Para alterar a cor da imagem vetorial, você pode usar diretamente o 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" />

Para mudar de cor programaticamente

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

getColor () está obsoleto
David

Como usá-lo para *** desenhável do TextView?
Hemant Kaushik

getColor (ResId) está obsoleto @David, mas getColor(ResId, Theme)não está. Ou você pode usar ResourcesCompat.getColor(getResources(), R.color.primary, null);se não se importa com o tema ... ou se o seu contexto / política delegar É uma atividade, você pode fazer getTheme()para esse último parâmetro.
Martin Marconcini

15

Atualmente, a solução de trabalho é o android: fillColor = "# FFFFFF"

Nada funcionou para mim, exceto a codificação embutida no vetor

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

No entanto, cor de preenchimento e tonalidade podem funcionar em breve. Consulte esta discussão para obter mais informações:

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

Além disso, as cores podem ficar no cache, portanto, a exclusão de aplicativos para todos os usuários pode ajudar.


7

O estúdio Android agora suporta vetores pré-pirulito. Nenhuma conversão PNG. Você ainda pode alterar a cor do preenchimento e ele funcionará.

No seu ImageView, use

 app:srcCompat="@drawable/ic_more_vert_24dp"

No seu arquivo de notas,

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

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

10
A questão é "como alterar vector cor de preenchimento", não "como usar ativos vector"
Leo Droidcoder

5

Atualização: AppCompatsuporte

Outras respostas suspeitando se android:tintfuncionará apenas em mais de 21 dispositivos, o AppCompat ( v23.2.0 e superior ) agora fornece um tratamento compatível com versões anteriores do atributo tint.

Portanto, o curso de ação seria usar AppCompatImageViewe app:srcCompat(no espaço de nome AppCompat) em vez de android:src(espaço de nome do Android).

Aqui está um exemplo (AndroidX: Este é 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 não se esqueça de ativar o suporte para desenho vetorial no gradle:

vectorDrawables.useSupportLibrary = true 

Apenas uma atualização. Hoje em dia o AppCompatImageViewestá sobandroidx.appcompat.widget.AppCompatImageView
Roc Boronat 03/07

2

Adicione esta biblioteca ao Gradle para ativar o vetor de cores desenhável nos antigos dispositivos Android.

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

e sincronize novamente o gradle. Eu acho que vai resolver o problema.


2

Se os vetores não estiverem mostrando cores definidas individualmente usando fillColor, eles poderão estar sendo configurados para um parâmetro de widget padrão.

Tente adicionar app:itemIconTint="@color/lime"ao activity_main.xml para definir um tipo de cor padrão para os ícones do 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


No Android studio 3.6, altere o svg xml neste campo: android: fillColor = "# FFFFC400"
a_subscriber

1

se você olhar para apoiar a versão antiga pré lolipop

use o mesmo código xml com algumas alterações

em vez de normal ImageView --> AppCompatImageView

ao invés de android:src --> app:srcCompat

aqui está um exemplo

<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ão se esqueça de atualizar seu gradle como @ Sayooj Valsan mencionar

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

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

Aviso Para qualquer um dos vetores, nunca forneça nunca sua referência de vetor a cores como esta, android:fillColor="@color/primary"forneça seu valor hexadecimal.


por isso nunca use @colorpara fillcolor?
HoseinIT

0

Para aqueles que não usam um ImageView, o seguinte funcionou para mim de maneira simples View(e, portanto, o comportamento deve se replicar em qualquer tipo de exibição)

<View
    android:background="@drawable/ic_reset"
    android:backgroundTint="@color/colorLightText" />
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.