Зміна кольору заливки на векторному об’єкті в Android Studio


169

Тепер Android Studio підтримує векторні активи на 21+ і створюватиме png для нижчих версій під час компіляції. У мене є векторний актив (від Material Icons), який я хочу змінити колір заливки. Це працює на 21+, але згенеровані PNG не змінюють колір. Чи є спосіб це зробити?

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

Відповіді:


333

Не редагуйте векторні активи безпосередньо. Якщо ви використовуєте векторний графічний малюнок у ImageButton, просто виберіть свій колір 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
підфарбовування працює лише на пристроях 21+, чи є у вас якісь пропозиції щодо пристроїв до льодяника
mudit

12
android: відтінок працює на всіх версіях Android з APIv1. Що ви маєте на увазі - DravableTint.
РРРР-ММ-ДД

31
android:tintповинен бути післяandroid:src
EmmanuelMess

5
А що drawableLeftв Button?
Пратік Бутані

8
@mudit спробуйте використати вектор з fillColor = "# colorvalue", не використовуйте посилання на колір @, оскільки вони працюють лише SDK 21+ для векторів (так не для генерованих PNG)
PieterAelse

95

Ти можеш це зробити.

АЛЕ ви не можете використовувати посилання @color для кольорів (..lame), інакше він буде працювати лише для 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
Це має бути прийнята відповідь! Посилання @color не працюють у векторах до Lollipop (тому вектор -> перетворення PNG) code.google.com/p/android/isissue/detail?id=186431
PieterAelse

5
Посилання @color тепер можна використовувати для атрибута fillColor для всіх версій Android, однак він не підтримує списки станів кольорів.
THEIT

Схоже, спосіб
складати

1
@ Що, що я маю, щоб це ввімкнути? Здається, це не працює для мене
urSus

@PieterAelse Я не впевнений, що робити, якщо ви хочете використовувати той самий актив, але з різним фоном (відтінки, як у попередній відповіді). У вашому рішенні у вас буде кілька примірників одного ресурсу, але з різним кольором заповнення
Антон Маков,

71

Як сказано в інших відповідях, не редагуйте вектор, що малюється безпосередньо, натомість ви можете підфарбовувати код java, наприклад:

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

А для простоти я створив клас помічників:

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

Для використання просто виконайте наступне:

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

Або:

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

    actionBar.setHomeAsUpIndicator(drawable);

Привіт Філіпе, дякую за вашу відповідь. У вас є бібліотека, фрагмент коду github, де ми можемо бачити ліцензію? дякую :)
Вінсент Д.

2
Nope Vicent, ліцензії взагалі немає. Рішення настільки просте, що я думаю, що використовуваний тут шаблон Builder не потрібен. Але будь-хто може скористатися цим рішенням і використовувати без ліцензії.
Філіпе Безерра де Суса

Чудова відповідь! Працює саме так, як мені потрібно
Eoin

1
@VincentD. Нижній колонтитул веб-сторінки говорить, що "внески користувачів ліцензовані під cc by-sa 3.0 з обов'язковим
приписом

Це працювало для мене з деякими змінами. Дякую за твою допомогу.
Андре Луїз Рейс

36

Для зміни кольору векторного зображення ви можете безпосередньо використовувати 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" />

Щоб змінити колір програмно

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

getColor () застаріло
Девід

Як використовувати його для малювання *** TextView?
Хемант Каушик

getColor (ResId) застарілий @David, але getColor(ResId, Theme)це не так. Або ви можете використовувати, ResourcesCompat.getColor(getResources(), R.color.primary, null);якщо вас не хвилює тема ... або якщо ваш делегат контексту / політики є активністю, ви можете зробити getTheme()цей останній параметр.
Мартін Маркончіні

15

В даний час робочим рішенням є Android: fillColor = "# FFFFFF"

Для мене нічого не працювало, крім жорсткого кодування у векторі

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

Однак шпаклівка та відтінок можуть працювати незабаром. Будь ласка, дивіться цю дискусію для отримання додаткової інформації:

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

Також кольори mighr впишуться в кеш, тому видалення програми для всіх користувачів може допомогти.


7

Android-студія тепер підтримує вектори перед льодяником. Перетворення PNG немає. Ви можете змінити колір заливки, і він спрацює.

У вас ImageView, використовуйте

 app:srcCompat="@drawable/ic_more_vert_24dp"

У вашому файлі gradle,

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

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

10
Питання - "як змінити колір заповнення векторної", а не "як використовувати векторний актив"
Leo Droidcoder

5

Оновлення: AppCompatпідтримка

Інші відповіді, підозрюючи, чи android:tintпрацюватимуть лише на 21+ пристроях, AppCompat ( v23.2.0 і новіші версії ) тепер забезпечує зворотне сумісне управління атрибутом відтінку.

Отже, курсом дії буде використання AppCompatImageViewта app:srcCompat(у просторі імен AppCompat) замість android:src(простір імен Android).

Ось приклад (AndroidX: Це 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" />

І не забудьте включити підтримку векторного малювання в gradle:

vectorDrawables.useSupportLibrary = true 

Просто оновлення. На сьогоднішній день AppCompatImageViewцеandroidx.appcompat.widget.AppCompatImageView
Рок Боронат

2

Додайте цю бібліотеку до Gradle, щоб увімкнути вектор кольорових зображень у старих Android-пристроях.

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

та повторно синхронізуйте градуси. Я думаю, це вирішить проблему.


2

Якщо вектори не відображають окремо встановлені кольори за допомогою fillColor, вони можуть бути встановлені за параметром віджета за замовчуванням.

Спробуйте додати app:itemIconTint="@color/lime"в Activity_main.xml, щоб встановити тип кольору за замовчуванням для значків віджетів.

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

VectorDravable @ developers.android


В студії Android 3.6 змінити svg xml у цьому полі: android: fillColor = "# FFFFC400"
a_subscriber

1

якщо ви хочете підтримати стару версію pre lolipop

використовувати той же код xml з деякими змінами

замість нормального ImageView --> AppCompatImageView

замість android:src --> app:srcCompat

ось приклад

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

не забудьте оновити свою ступінь як згадка @ Sayooj Valsan

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

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

Зауважте, що будь-який вектор використання ніколи ніколи не вказує на ваш векторний посилання на колір, як цей, android:fillColor="@color/primary"надає його шістнадцяткове значення.


чому ніколи не використовувати @colorдля fillcolor?
HoseinIT

0

Для тих, хто не використовує ImageView, наступне працювало для мене зрозуміло View(і, отже, поведінка повинна повторюватись у будь-якому вигляді)

<View
    android:background="@drawable/ic_reset"
    android:backgroundTint="@color/colorLightText" />
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.