Zmień kolor wypełnienia zasobu wektorowego w Android Studio


169

Android Studio obsługuje teraz zasoby wektorowe w wersjach 21+ i generuje pliki PNG dla niższych wersji w czasie kompilacji. Mam zasób wektorowy (z ikon materiałów), dla którego chcę zmienić kolor wypełnienia. Działa to na 21+, ale wygenerowane png nie zmieniają koloru. Czy jest na to sposób?

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

Odpowiedzi:


333

Nie edytuj bezpośrednio zasobów wektorowych. Jeśli używasz wektora do rysowania w ImageButton, po prostu wybierz kolor w 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
barwienie działa tylko na 21+ urządzeniach, czy masz jakieś sugestie dotyczące urządzeń pre-lollipop
— mudit

12
android: tint działa na wszystkich wersjach Androida od APIv1. Masz na myśli drawableTint.
— RRRR-MM-DD

31
android:tintmusi być poandroid:src
— EmmanuelMess

5
A co drawableLeftw Buttonśrodku?
— Pratik Butani

8
@mudit spróbuj użyć wektora z fillColor = "# colorvalue", nie używaj odniesienia @ color, ponieważ działają one tylko w SDK 21+ dla wektorów (a więc nie dla wygenerowanych
— plików

95

Możesz to zrobić.

ALE nie możesz używać odniesień @color do kolorów (..lame), w przeciwnym razie będzie działać tylko dla 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
To powinna być akceptowana odpowiedź! @color odwołania nie działają w wektorach przed Lollipopem (więc wektor -> konwersja PNG) code.google.com/p/android/issues/detail?id=186431
— PieterAelse

5
Odniesienia @color mogą być teraz używane dla atrybutu fillColor dla wszystkich wersji Androida, jednak nie obsługuje on list stanów kolorów.
— TheIT

Wygląda na to, że sposób tworzenia list stanów wektorów jest za pomocą AnimatedStateListDrawable s
— gMale

1
@TheIT co mam, aby to włączyć? Wydaje się, że nie działa dla mnie
— urSus

@PieterAelse Nie jestem pewien, co zrobić, jeśli chcesz użyć tego samego zasobu, ale z różnymi tłami (odcienie jak w poprzedniej odpowiedzi). W swoim rozwiązaniu będziesz mieć kilka instancji tego samego zasobu, ale z innym kolorem wypełnienia
— Anton Makov,

71

Jak powiedziano w innych odpowiedziach, nie edytuj bezpośrednio wektora do rysowania, zamiast tego możesz odcień w kodzie java, na przykład:

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

Dla uproszczenia stworzyłem klasę pomocniczą:

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

Aby użyć, wykonaj następujące czynności:

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

Lub:

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

    actionBar.setHomeAsUpIndicator(drawable);

Cześć Filipe, dziękuję za odpowiedź. Czy masz bibliotekę, github z wyciętym kodem, gdzie możemy zobaczyć licencję? dzięki :)
— Vincent D.

2
Nie, Vicent, żadnej licencji. Rozwiązanie jest tak proste, że wydaje mi się, że użyty tutaj wzorzec Builder nie jest konieczny. Ale każdy może skorzystać z tego rozwiązania i używać go bez licencji.
— Filipe Bezerra de Sousa

Świetna odpowiedź! Działa dokładnie tak, jak potrzebuję
— Eoin

1
@VincentD. Stopka strony internetowej SO mówi: „Wkłady użytkowników licencjonowane na podstawie CC by-sa 3.0 z wymaganym
— podaniem źródła

U mnie zadziałało z pewnymi zmianami. Dziękuję za pomoc.
— André Luiz Reis

36

Aby zmienić kolor obrazu wektorowego, możesz bezpośrednio użyć 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" />

Aby programowo zmienić kolor

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

Funkcja getColor () jest przestarzała
— David,

Jak go używać do rysowania *** TextView?
— Hemant Kaushik

getColor (ResId) jest przestarzała @David, ale getColor(ResId, Theme)tak nie jest. Lub możesz użyć, ResourcesCompat.getColor(getResources(), R.color.primary, null);jeśli nie dbasz o motyw… lub jeśli delegat kontekstu / polityki JEST działaniem, możesz to zrobić getTheme()dla tego ostatniego parametru.
— Martin Marconcini

15

Obecnie działającym rozwiązaniem jest android: fillColor = "# FFFFFF"

Nic nie działało dla mnie poza twardym kodowaniem w wektorze

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

Jednak wypełnienie i tinta mogą wkrótce działać. Więcej informacji można znaleźć w tej dyskusji:

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

Również kolory pozostają w pamięci podręcznej, więc usunięcie aplikacji dla wszystkich użytkowników może pomóc.


7

Android studio obsługuje teraz wektory pre-lollipop. Brak konwersji do formatu PNG. Nadal możesz zmienić kolor wypełnienia i będzie działać.

W swoim ImageView użyj

 app:srcCompat="@drawable/ic_more_vert_24dp"

W pliku ocen

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

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

10
Pytanie brzmi „jak zmienić kolor wypełnienia wektora”, a nie „jak używać zasobu wektorowego”
— Leo Droidcoder

5

Aktualizacja: AppCompatwsparcie

Inne odpowiedzi podejrzewające, czy android:tintbędą działać tylko na urządzeniach 21+, AppCompat ( wersja 23.2.0 i nowsze ) zapewnia teraz kompatybilną wstecz obsługę atrybutu tint.

Tak więc, działaniem byłoby użycie AppCompatImageViewi app:srcCompat(w przestrzeni nazw AppCompat) zamiast android:src(przestrzeń nazw Androida).

Oto przykład (AndroidX: to jest 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" />

I nie zapomnij włączyć obsługi grafiki wektorowej w Gradle:

vectorDrawables.useSupportLibrary = true 

Tylko aktualizacja. Obecnie AppCompatImageViewjest poniżejandroidx.appcompat.widget.AppCompatImageView
— Roc Boronat

2

Dodaj tę bibliotekę do Gradle, aby umożliwić rysowanie wektorów kolorów na starych urządzeniach z Androidem.

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

i ponownie zsynchronizuj gradle. Myślę, że to rozwiąże problem.


2

Jeśli wektory nie pokazują indywidualnie ustawionych kolorów przy użyciu fillColor, mogą być ustawione na domyślny parametr widgetu.

Spróbuj dodać app:itemIconTint="@color/lime"do pliku activity_main.xml, aby ustawić domyślny typ koloru ikon widżetów.

<?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


W Android Studio 3.6 zmiana w svg xml w tym polu: android: fillColor = "# FFFFC400"
— a_subscriber

1

jeśli chcesz obsługiwać starszą wersję przed lolipopem

użyj tego samego kodu XML z pewnymi zmianami

zamiast normalnego ImageView --> AppCompatImageView

zamiast android:src --> app:srcCompat

oto przykład

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

nie zapomnij zaktualizować swojego gradle jako wzmianka @ Sayooj Valsan

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

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

Zauważ, że żadnemu wektorowi nie wolno nigdy podawać odniesienia do koloru takiego jak ten, android:fillColor="@color/primary"podając jego wartość szesnastkową.


Dlatego nigdy nie należy używać @colordo fillcolor?
— HoseinIT

0

Dla tych, którzy nie używają znaku ImageView, poniższe działały dla mnie na zwykłym View(i dlatego zachowanie powinno się powielać na każdym rodzaju widoku)

<View
    android:background="@drawable/ic_reset"
    android:backgroundTint="@color/colorLightText" />
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.