在Android Studio中更改矢量资产的填充颜色

216

现在,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"/>

18个回答

415

不要直接编辑矢量资源。 如果您在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" />

25
着色功能仅适用于安卓版本21及以上的设备,你有没有针对早期版本的安卓系统(Lollipop之前)的建议? - mudit
12
android:tint可以在APIv1版本及以后的所有Android版本上使用。你所指的应该是drawableTint。 - YYYY-MM-DD
38
android:tint 必须在 android:src 后面。 - EmmanuelMess
7
Button 中的 drawableLeft 是什么意思? - Pratik Butani
9
尝试使用fillColor="#colorvalue"的向量,不要使用@颜色引用,因为它们仅适用于SDK 21+的向量(因此不适用于生成的PNG文件)。 - PieterAelse
显示剩余8条评论

109

你可以做到。

但是你不能使用@color引用颜色(太糟糕了),否则它只能在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 引用在 Android 5.0 之前的向量图中无效(因此需要将向量图转换为 PNG 格式)。详情请见:https://code.google.com/p/android/issues/detail?id=186431 - PieterAelse
6
@color 引用现在可以用于所有 Android 版本的 fillColor 属性,但不支持颜色状态列表。 - TheIT
1
看起来使用AnimatedStateListDrawable是实现矢量状态列表的方法。 - gMale
1
@TheIT,我需要启用什么?似乎对我不起作用。 - urSus
1
即使直接设置颜色,仍然无法工作。仍然是白色。 - Waldmann
显示剩余3条评论

74

正如其他答案所说,不要直接编辑矢量图形,而是可以在Java代码中进行着色,像这样:

如其他回答所述,请勿直接编辑矢量图形,而应在Java代码中进行染色,例如:

如其他答案所述,请勿直接编辑向量绘图文件,您可以在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);

嗨,Filipe,感谢您的回答。您是否有一个库、代码片段或者Github链接可以让我们查看许可证?谢谢 :) - Vincent D.
2
不需要许可证,Vicent。解决方案非常简单,我猜在这里使用生成器模式是不必要的。但任何人都可以从这个解决方案中受益,并且可以免费使用。 - Filipe Bezerra de Sousa
1
@VincentD。SO网页底部显示“用户贡献基于cc by-sa 3.0许可, 需要署名”。 - shelll
1
经过一些更改,它对我起作用了。谢谢你的帮助。 - André Luiz Reis
这应该是被接受的答案。完美地解决了问题! - anshajkhare
显示剩余2条评论

46

要更改矢量图像的颜色,您可以直接使用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()已被弃用。 - David
如何在TextView的drawable***中使用它? - Hemant Kaushik
getColor(ResId)已被弃用@David,但getColor(ResId, Theme)没有。或者,如果您不关心主题,您可以使用ResourcesCompat.getColor(getResources(), R.color.primary, null);…或者如果您的上下文/策略委托是一个活动,您可以为最后一个参数使用getTheme() - Martin Marconcini

16

目前的解决方案是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"/>

然而,fillcolor和tint可能很快就会起作用。请参阅此讨论以获取更多信息:

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

此外,颜色可能会在缓存中保留,因此删除所有用户的应用程序可能有所帮助。


12

更新:支持AppCompat

其他答案猜测android:tint是否只适用于21+设备,AppCompat(v23.2.0及以上版本现在提供了对色彩属性的向后兼容处理。

因此,行动的方式是使用AppCompatImageViewapp: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 

2
只是一个更新。现在AppCompatImageView位于androidx.appcompat.widget.AppCompatImageView下面。 - Roc Boronat

7

现在Android Studio支持矢量图,即使在低版本的设备上也无需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'

13
问题是“如何更改矢量填充颜色”,而不是“如何使用矢量素材”。 - Leo DroidCoder

4
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24"
    android:tint="//Your Color Code//">
  <path
      android:fillColor="@android:color/white"
      android:pathData="M11,9.16V2c-5,0.5 -9,4.79 -9,10s4,9.5 9"/>
</vector>

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community
非常感谢!这是改变颜色的最简单方法。android:tint = "//您的颜色代码//" - Shubham Nanche

3
如果向量不使用fillColor单独显示颜色,则可能会将它们设置为默认小部件参数。尝试在activity_main.xml中添加app:itemIconTint="@color/lime",为小部件图标设置默认颜色类型。
<?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>

{{link1:VectorDrawable @ developers.android}}


在Android Studio 3.6中更改SVG XML中的此字段:android:fillColor="#FFFFC400"。 - Alexei

2
将此库添加到Gradle中,以启用旧Android设备中的彩色矢量可绘制对象。
compile 'com.android.support:palette-v7:26.0.0-alpha1'

并重新同步Gradle。我认为这样可以解决问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接