Thay đổi màu tô trên tài sản vector trong Android Studio


169

Android Studio hiện hỗ trợ tài sản vector trên 21+ và sẽ tạo pngs cho các phiên bản thấp hơn tại thời điểm biên dịch. Tôi có một tài sản vectơ (từ Biểu tượng Vật liệu) mà tôi muốn thay đổi màu tô. Điều này hoạt động trên 21+, nhưng pngs được tạo ra không thay đổi màu sắc. Có cách nào để làm việc này không?

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

Câu trả lời:


332

Đừng chỉnh sửa trực tiếp các tài sản vector. Nếu bạn đang sử dụng một vectơ có thể vẽ trong ImageButton, chỉ cần chọn màu của bạn 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
pha màu chỉ hoạt động trên 21 thiết bị, bạn có gợi ý nào cho các thiết bị tiền kẹo mút không
Mudit

12
android: tint hoạt động trên tất cả các phiên bản Android kể từ APIv1. Ý bạn là drawableTint.
YYYY-MM-DD

31
android:tintphải sauandroid:src
EmmanuelMess

5
Còn drawableLefttrong Button?
Pratik Butani

8
@mudit hãy thử sử dụng một vectơ với fillColor = "# colorvalue", không sử dụng tham chiếu màu @ vì chúng chỉ hoạt động SDK 21+ cho các vectơ (không phải cho các PNG được tạo)
PieterAelse

95

Bạn có thể làm được.

NHƯNG bạn không thể sử dụng tài liệu tham khảo @color cho màu sắc (..lame), nếu không, nó sẽ chỉ hoạt động cho 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
Đây phải là câu trả lời được chấp nhận! Tài liệu tham khảo @color không hoạt động trong các vectơ trước Lollipop (vì vậy vectơ -> chuyển đổi PNG) code.google.com/p/android/issues/detail?id=186431
PieterAelse

5
Tham chiếu @color hiện có thể được sử dụng cho thuộc tính fillColor cho tất cả các phiên bản Android, tuy nhiên nó không hỗ trợ danh sách trạng thái màu.
TheIT

Có vẻ như cách thực hiện danh sách trạng thái vector là với AnimatedStateListDrawable s
gMale

1
@TheIT tôi phải kích hoạt cái gì? Dường như không hoạt động với tôi
urSus

@PieterAelse Tôi không chắc chắn, nếu bạn muốn sử dụng cùng một tài sản nhưng với các nền tảng khác nhau (gợi ý như trong câu trả lời trước). Trong giải pháp của bạn, bạn sẽ có một số trường hợp của cùng một tài nguyên nhưng với màu tô khác nhau
Anton Makov

71

Như đã nói trong các câu trả lời khác, đừng chỉnh sửa trực tiếp vector có thể vẽ, thay vào đó bạn có thể tô màu trong mã java, như thế:

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

Và để đơn giản, tôi đã tạo ra một lớp trợ giúp:

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

Để sử dụng chỉ cần làm như sau:

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

Hoặc là:

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

    actionBar.setHomeAsUpIndicator(drawable);

Xin chào Filipe, cảm ơn câu trả lời của bạn. Bạn có một thư viện, mã nguồn github nơi chúng tôi có thể xem giấy phép? cảm ơn :)
Vincent D.

2
Nope Vicent, không có giấy phép nào cả. Giải pháp đơn giản đến mức tôi đoán rằng mẫu Builder được sử dụng ở đây là không cần thiết. Nhưng bất cứ ai cũng có thể được hưởng lợi từ giải pháp này và sử dụng mà không cần giấy phép.
Filipe Bezerra de Sousa

Câu trả lời chính xác! Hoạt động chính xác như tôi cần
Eoin

1
@VincentD. Chân trang web SO cho biết "đóng góp của người dùng được cấp phép theo cc by-sa 3.0 với yêu cầu ghi công"
shelll

Nó làm việc cho tôi với một số thay đổi. Cảm ơn sự giúp đỡ của bạn.
André Luiz Reis

36

Để thay đổi màu hình ảnh vector, bạn có thể trực tiếp sử dụng 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" />

Thay đổi màu sắc theo chương trình

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

getColor () không được dùng nữa
David

Làm cách nào để sử dụng nó cho drawable *** của TextView?
Hemant Kaushik

getColor (ResId) không được chấp nhận @David, nhưng getColor(ResId, Theme)không được. Hoặc bạn có thể sử dụng ResourcesCompat.getColor(getResources(), R.color.primary, null);nếu bạn không quan tâm đến chủ đề, hoặc nếu đại diện chính sách / bối cảnh của bạn là một hoạt động, bạn có thể thực hiện getTheme()cho tham số cuối cùng đó.
Martin Marconcini

15

Hiện tại, giải pháp làm việc là android: fillColor = "# FFFFFF"

Không có gì làm việc cho tôi ngoại trừ mã hóa cứng trong vector

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

Tuy nhiên, fillcolor và tint có thể hoạt động sớm. Vui lòng xem cuộc thảo luận này để biết thêm thông tin:

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

Ngoài ra các màu mighr dính trong bộ đệm để xóa ứng dụng cho tất cả người dùng có thể giúp ích.


7

Android studio hiện hỗ trợ vectơ trước kẹo mút. Không có chuyển đổi PNG. Bạn vẫn có thể thay đổi màu tô của bạn và nó sẽ hoạt động.

Trong ImageView của bạn, sử dụng

 app:srcCompat="@drawable/ic_more_vert_24dp"

Trong tập tin lớp của bạn,

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

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

10
Câu hỏi là "làm thế nào để thay đổi màu tô màu vector", chứ không phải "cách sử dụng tài sản vectơ"
Leo Droidcoder

5

Cập nhật: AppCompathỗ trợ

Các câu trả lời khác nghi ngờ nếu android:tintchỉ hoạt động trên 21 thiết bị, AppCompat ( v23.2.0 trở lên ) hiện cung cấp khả năng xử lý tương thích ngược của thuộc tính tint.

Vì vậy, quá trình hành động sẽ là sử dụng AppCompatImageViewapp:srcCompat(trong không gian tên AppCompat) thay vì android:src(không gian tên Android).

Dưới đây là một ví dụ (AndroidX: Đây là 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" />

Và đừng quên bật hỗ trợ có thể vẽ vector trong lớp:

vectorDrawables.useSupportLibrary = true 

Chỉ là một bản cập nhật. Ngày nay, AppCompatImageViewbên dướiandroidx.appcompat.widget.AppCompatImageView
Roc Boronat

2

Thêm thư viện này vào Gradle để cho phép vẽ vector màu trong các Thiết bị Android cũ.

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

và đồng bộ lại lớp. Tôi nghĩ rằng nó sẽ giải quyết vấn đề.


2

Nếu các vectơ không hiển thị màu được đặt riêng lẻ bằng fillColor thì chúng có thể được đặt thành tham số widget mặc định.

Hãy thử thêm app:itemIconTint="@color/lime" vào Activity_main.xml để đặt loại màu mặc định cho các biểu tượng 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


Trong studio Android 3.6 thay đổi trong Svg xml trường này: android: fillColor = "# FFFFC400"
a_subscacker

1

Nếu bạn muốn hỗ trợ phiên bản cũ trước lolipop

sử dụng cùng mã xml với một số thay đổi

thay vì bình thường ImageView --> AppCompatImageView

thay vì android:src --> app:srcCompat

đây là ví dụ

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

đừng quên cập nhật lớp của bạn như @ Sayooj Valsan đề cập

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

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

Lưu ý Đối với bất kỳ một vectơ nào, đừng bao giờ đưa ra tham chiếu vectơ của bạn cho màu như thế này android:fillColor="@color/primary"cho giá trị hex của nó.


Tại sao không bao giờ sử dụng @colorcho fillcolor?
HoseinIT

0

Đối với những người không sử dụng một ImageView, những điều sau đây làm việc cho tôi một cách đơn giản View(và do đó hành vi sẽ nhân rộng trên bất kỳ loại quan điểm nào)

<View
    android:background="@drawable/ic_reset"
    android:backgroundTint="@color/colorLightText" />
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.