ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Android 中更改 Drawable 的颜色?

我正在开发一个 android 应用程序,并且我有一个从源图像加载的可绘制对象。在这张图片上,我想将所有白色像素转换为不同的颜色,比如蓝色,然后缓存生成的 Drawable 对象,以便以后使用。

例如,假设我有一个 20x20 的 PNG 文件,中间有一个白色圆圈,圆圈外的所有内容都是透明的。将那个白色圆圈变成蓝色并缓存结果的最佳方法是什么?如果我想使用该源图像创建几个新的可绘制对象(比如蓝色、红色、绿色、橙色等),答案会改变吗?

我猜我会想以某种方式使用 ColorMatrix,但我不确定如何。

你终于以某种方式让它工作了吗?我确实在下面看到了很多答案,我也尝试了很多答案,但没有任何效果。我目前有一个白色方块,我想根据需要每次都给它涂上不同的颜色,这样我就不必创建静态资源了。请建议,因为我仍在等待全白色的简单形状的工作解决方案。
@omkar.ghaisas 我构建了一个名为 SillyAndroid 的库,其中包含一个通用的着色类,并对可绘制对象和文本进行各种着色。您可以在 github.com/milosmns/silly-android 查看。该课程位于 /sillyandroid/src/main/java/me/angrybyte/sillyandroid/extras/Coloring.java

t
thom_nic

我认为您实际上可以只使用 Drawable.setColorFilter( 0xffff0000, Mode.MULTIPLY )。这会将白色像素设置为红色,但我认为它不会影响透明像素。

请参阅Drawable#setColorFilter


当drawable是单色时这会很好用,当它是白色时效果更好。
如果颜色发生动态变化(例如在适配器中),则可绘制对象必须是可变的。示例:Drawable.mutate().setColorFilter( 0xffff0000, Mode.MULTIPLY) 更多信息:curious-creature.org/2009/05/02/drawable-mutations
是的,它特别适合突出显示(更亮、更暗或为灰度图像添加色调。)我使用这个技巧来切换按钮,其中“未选中”是灰度,“选中”是我应用程序调色板中的粗体颜色。我个人觉得它比自定义复选框更容易。
这正是我一直在寻找的,尽管我们不能在 XML (except for on 5.0+) 中做到这一点非常烦人。 AppCompat 中甚至不支持着色,因此每次使用图标时我们都不得不调用 setColorFilter,而不是选择具有不同颜色的选择器。尽管如此,它还是比直接编辑 png 并拥有额外的静态资源好多更好的解决方案。
如果您的源图标颜色较深,则乘法将不起作用。要使用目标颜色绘制源图标形状,请使用 SRC_INmyImage.getDrawable().mutate().setColorFilter(getResources().getColor(R.color.icon_grey), PorterDuff.Mode.SRC_IN);
n
nhahtdh

试试这个代码:

ImageView lineColorCode = (ImageView)convertView.findViewById(R.id.line_color_code);
int color = Color.parseColor("#AE6118"); //The color u want             
lineColorCode.setColorFilter(color);

C
Community

我知道这个问题是在 Lollipop 之前提出的,但我想在 Android 5.+ 上添加一个很好的方法来做到这一点。您制作了一个引用原始文件的 xml 可绘制对象并在其上设置色调,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<bitmap
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/ic_back"
    android:tint="@color/red_tint"/>

这也是最新支持库的一部分吗?
不,这只有助于一些简单的小部件。
Tint 通过 DrawableCompat 在 support-v4 中
很酷,我会调查并相应地更新它。
Fresco 不支持这种类型的可绘制对象
P
Pei

新的支持 v4 将色调带回 api 4。

你可以这样做

public static Drawable setTint(Drawable d, int color) {
    Drawable wrappedDrawable = DrawableCompat.wrap(d);
    DrawableCompat.setTint(wrappedDrawable, color);
    return wrappedDrawable;
}

从支持库 22 开始。
这是首选的解决方案,自从 lollipop 发布以来,着色 drawable 一直是旧 API 中的一个灰色区域。这打破了这个障碍!我不知道这个 - 谢谢@Pei
当心!您应该改变新包装的可绘制“#mutate()”以避免与状态相关的问题。请参阅stackoverflow.com/a/44593641/5555218
s
sfmirtalebi

如果您有一个纯色的可绘制对象并且您想将其更改为不同的纯色,您可以使用 ColorMatrixColorFilter。透明度得以保留。

int iColor = Color.parseColor(color);

int red   = (iColor & 0xFF0000) / 0xFFFF;
int green = (iColor & 0xFF00) / 0xFF;
int blue  = iColor & 0xFF;

float[] matrix = { 0, 0, 0, 0, red,
                   0, 0, 0, 0, green,
                   0, 0, 0, 0, blue,
                   0, 0, 0, 1, 0 };

ColorFilter colorFilter = new ColorMatrixColorFilter(matrix);
drawable.setColorFilter(colorFilter);

如果您想使用颜色资源而不是字符串(#ff0000 等),您可以使用例如 int iColor = getResources().getColor(R.color.primary)
这可行,但我有复选框,我想保留中间的白色勾号。有什么建议吗?
Ben 的评论中的代码现在已被弃用。相反,您可以使用 int iColor = ContextCompat.getColor(context, R.color.primary);
绝妙的答案!!谢谢大家!
@Mike Hill 好的,解释一下为什么你放了超过 20 种颜色。你需要在数组中插入超过 20 种颜色,否则它会因 java.lang.ArrayIndexOutOfBoundsException 而崩溃
t
touhid udoy

我还将 ImageView 用于图标(在 ListView 或设置屏幕中)。但我认为有更简单的方法可以做到这一点。

使用 tint 更改所选图标上的颜色叠加。

在 xml 中,

android:tint="@color/accent"
android:src="@drawable/ic_event" 

工作正常,因为它来自 AppCompat


这里有很多很好的答案,但对于 OP 的问题,这是最好和最简单的解决方案。
对于 api 22 及更高版本
@philipoghenerobobalogun 我在 api 19 上看到了这个
k
kirtan403

您应该对所有 API 执行此操作:

Drawable myIcon = getResources().getDrawable( R.drawable.button ); 
ColorFilter filter = new LightingColorFilter( Color.BLACK, Color.BLACK);
myIcon.setColorFilter(filter);

这以可接受的方式解决了这个问题。但是在过滤颜色时,可能会发生(发生在我身上)结果颜色与预期不符的情况。要变亮的颜色。我所做的是:` new LightingColorFilter(Color.parseColor("#FF000000"), myFinalColor) `
强调我认为前一个评论者所说的话,如果 LightingColorFilter 中的 2 个参数不同,则此解决方案会更改颜色,例如,ColorFilter filter = new LightingColorFilter(Color.BLACK, Color.LTGRAY); 将在可绘制对象中将黑色变为灰色。
当 alpha 用于色调颜色时,这似乎不起作用。
如文档所示,它不会更改 Alpha 通道,因此不会使任何东西或多或少透明:developer.android.com/reference/android/graphics/…
M
Matt McMinn

我可以使用以下代码来做到这一点,该代码取自一个活动(布局非常简单,仅包含一个 ImageView,此处不发布)。

private static final int[] FROM_COLOR = new int[]{49, 179, 110};
private static final int THRESHOLD = 3;

public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.test_colors);

    ImageView iv = (ImageView) findViewById(R.id.img);
    Drawable d = getResources().getDrawable(RES);
    iv.setImageDrawable(adjust(d));
}

private Drawable adjust(Drawable d)
{
    int to = Color.RED;

    //Need to copy to ensure that the bitmap is mutable.
    Bitmap src = ((BitmapDrawable) d).getBitmap();
    Bitmap bitmap = src.copy(Bitmap.Config.ARGB_8888, true);
    for(int x = 0;x < bitmap.getWidth();x++)
        for(int y = 0;y < bitmap.getHeight();y++)
            if(match(bitmap.getPixel(x, y))) 
                bitmap.setPixel(x, y, to);

    return new BitmapDrawable(bitmap);
}

private boolean match(int pixel)
{
    //There may be a better way to match, but I wanted to do a comparison ignoring
    //transparency, so I couldn't just do a direct integer compare.
    return Math.abs(Color.red(pixel) - FROM_COLOR[0]) < THRESHOLD &&
        Math.abs(Color.green(pixel) - FROM_COLOR[1]) < THRESHOLD &&
        Math.abs(Color.blue(pixel) - FROM_COLOR[2]) < THRESHOLD;
}

我从哪里获得阈值或 FROM_COLOR?
这些只是我定义的常量;我刚刚编辑了答案以包含它们。
谢谢;) 试过了,但不适合我遇到的问题。尝试了 setColorFilter,这可行,但是缩放 .9.png 图像时出现问题。所以如果你知道为什么,请回答我的问题。 stackoverflow.com/questions/5884481/…
彩色滤光片要容易得多。
R
Ricard

您可以使用 Android 支持兼容库来解决它。 :)

 // mutate to not share its state with any other drawable
 Drawable drawableWrap = DrawableCompat.wrap(drawable).mutate();
 DrawableCompat.setTint(drawableWrap, ContextCompat.getColor(getContext(), R.color.your_color))

@AmitabhaBiswas 为什么你完全改错了我的答案?一部分一部分。 1. getResources().getDrawable() 已弃用!! 2. 我使用支持库是因为我不想关心 Andorid Api 版本。 3. 我不想重绘 Drawable.... 如果你想展示另一种方法,请写下你自己的答案。
@AmitabhaBiswas 此外,可绘制对象在资源中的所有 getDrawable 之间共享,因此需要 mutate() 调用才能更改可绘制对象的色调,而无需更改与该资源 ID 关联的所有可绘制对象。
这是最好的答案!在图像视图中包装可绘制并不能解决问题。
.mutate() 让我开心。如果在某些项目列表中工作,那真的很好用
D
David Douglas

在您的活动中,您可以使用单一颜色为您的 PNG 图像资源着色:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    myColorTint();
    setContentView(R.layout.activity_main);
}

private void myColorTint() {
    int tint = Color.parseColor("#0000FF"); // R.color.blue;
    PorterDuff.Mode mode = PorterDuff.Mode.SRC_ATOP;
    // add your drawable resources you wish to tint to the drawables array...
    int drawables[] = { R.drawable.ic_action_edit, R.drawable.ic_action_refresh };
    for (int id : drawables) {
        Drawable icon = getResources().getDrawable(id);
        icon.setColorFilter(tint,mode);
    }
}

现在,当您使用 R.drawable.* 时,它应该使用所需的色调进行着色。如果您需要其他颜色,那么您应该能够 .mutate() 可绘制对象。


M
Martin Nowosad

如果您将可绘制设置为 ImageView,则可以使用 1 衬里:

yourImageView.setColorFilter(context.getResources().getColor(R.color.YOUR_COLOR_HERE);

H
Hamidreza Sadegh
view.getDrawable().mutate().setColorFilter(0xff777777, PorterDuff.Mode.MULTIPLY); 

感谢@sabadow


不推荐使用 setColorFilter
M
Mehatab

此代码段对我有用:

PorterDuffColorFilter porterDuffColorFilter = new PorterDuffColorFilter(getResources().getColor(R.color.your_color),PorterDuff.Mode.MULTIPLY);

imgView.getDrawable().setColorFilter(porterDuffColorFilter);
imgView.setBackgroundColor(Color.TRANSPARENT)

M
Mouaad Abdelghafour AITALI

为时已晚,但万一有人需要它:

   fun setDrawableColor(drawable: Drawable, color: Int) :Drawable {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            drawable.colorFilter = BlendModeColorFilter(color, BlendMode.SRC_ATOP)
            return drawable
        } else {
            drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
            return drawable
        }
    }

t
toni

这适用于所有有背景的东西:

文本视图,按钮...

TextView text = (TextView) View.findViewById(R.id.MyText);
text.setBackgroundResource(Icon);    
text.getBackground().setColorFilter(getResources().getColor(Color), PorterDuff.Mode.SRC_ATOP);

P
Pankaj

有很多解决方案,但没有人建议如果颜色资源 xml 文件已经有颜色,那么我们也可以直接从那里选择,如下所示:

ImageView imageView = (ImageView) findViewById(R.id.imageview);
imageView.setColorFilter(getString(R.color.your_color));

s
superjos

查看此示例代码“ColorMatrixSample.java

/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.apis.graphics;

import com.example.android.apis.R;

import android.app.Activity;
import android.content.Context;
import android.graphics.*;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;

public class ColorMatrixSample extends GraphicsActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new SampleView(this));
    }

    private static class SampleView extends View {
        private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        private ColorMatrix mCM = new ColorMatrix();
        private Bitmap mBitmap;
        private float mSaturation;
        private float mAngle;

        public SampleView(Context context) {
            super(context);

            mBitmap = BitmapFactory.decodeResource(context.getResources(),
                                                   R.drawable.balloons);
        }

        private static void setTranslate(ColorMatrix cm, float dr, float dg,
                                         float db, float da) {
            cm.set(new float[] {
                   2, 0, 0, 0, dr,
                   0, 2, 0, 0, dg,
                   0, 0, 2, 0, db,
                   0, 0, 0, 1, da });
        }

        private static void setContrast(ColorMatrix cm, float contrast) {
            float scale = contrast + 1.f;
               float translate = (-.5f * scale + .5f) * 255.f;
            cm.set(new float[] {
                   scale, 0, 0, 0, translate,
                   0, scale, 0, 0, translate,
                   0, 0, scale, 0, translate,
                   0, 0, 0, 1, 0 });
        }

        private static void setContrastTranslateOnly(ColorMatrix cm, float contrast) {
            float scale = contrast + 1.f;
               float translate = (-.5f * scale + .5f) * 255.f;
            cm.set(new float[] {
                   1, 0, 0, 0, translate,
                   0, 1, 0, 0, translate,
                   0, 0, 1, 0, translate,
                   0, 0, 0, 1, 0 });
        }

        private static void setContrastScaleOnly(ColorMatrix cm, float contrast) {
            float scale = contrast + 1.f;
               float translate = (-.5f * scale + .5f) * 255.f;
            cm.set(new float[] {
                   scale, 0, 0, 0, 0,
                   0, scale, 0, 0, 0,
                   0, 0, scale, 0, 0,
                   0, 0, 0, 1, 0 });
        }

        @Override protected void onDraw(Canvas canvas) {
            Paint paint = mPaint;
            float x = 20;
            float y = 20;

            canvas.drawColor(Color.WHITE);

            paint.setColorFilter(null);
            canvas.drawBitmap(mBitmap, x, y, paint);

            ColorMatrix cm = new ColorMatrix();

            mAngle += 2;
            if (mAngle > 180) {
                mAngle = 0;
            }

            //convert our animated angle [-180...180] to a contrast value of [-1..1]
            float contrast = mAngle / 180.f;

            setContrast(cm, contrast);
            paint.setColorFilter(new ColorMatrixColorFilter(cm));
            canvas.drawBitmap(mBitmap, x + mBitmap.getWidth() + 10, y, paint);

            setContrastScaleOnly(cm, contrast);
            paint.setColorFilter(new ColorMatrixColorFilter(cm));
            canvas.drawBitmap(mBitmap, x, y + mBitmap.getHeight() + 10, paint);

            setContrastTranslateOnly(cm, contrast);
            paint.setColorFilter(new ColorMatrixColorFilter(cm));
            canvas.drawBitmap(mBitmap, x, y + 2*(mBitmap.getHeight() + 10),
                              paint);

            invalidate();
        }
    }
}

相关 API 可用here


这确实显示了如何使用 ColorMatrix,但我没有看到如何使用它来获得我正在寻找的结果。
d
deadfish

根据 isWorking 字段更改可绘制颜色的简短示例。

我的形状xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <solid android:color="@android:color/holo_blue_bright" />
    <corners android:radius="30dp" />
    <size
        android:height="15dp"
        android:width="15dp" />
</shape>

我的改变方法:

private Drawable getColoredDrawable(int drawableResId, boolean isworking) {
    Drawable d = getResources().getDrawable(R.drawable.shape);
    ColorFilter filter = new LightingColorFilter(
            isworking ? Color.GREEN : Color.RED,
            isworking ? Color.GREEN : Color.RED);
    d.setColorFilter(filter);
    return d;
}

使用示例:

text1.setCompoundDrawablesWithIntrinsicBounds(getColoredDrawable(R.drawable.shape, isworking()), null, null, null);

A
Adil Soomro
Int color = Color.GRAY; 
// or int color = Color.argb(123,255,0,5);
// or int color = 0xaaff000;

在 XML /res/values/color.xml

<?xml version="1.0" encoding="utf-8">
<resources>
    <color name="colorRed">#ff0000</color>
</resoures> 

Java 代码

int color = ContextCompat.getColor(context, R.color.colorRed);

GradientDrawable drawableBg = yourView.getBackground().mutate();
drawableBg.setColor(color);

J
Jay Parikh

它适用于一些简单的drawables。我在一个简单的带圆角的纯色矩形上使用它,并且需要用不同的布局改变颜色。

尝试这个

android:backgroundTint="#101010"

S
Saurabh

试试 android:backgroundTint="@color/quantum_black_100"


T
Top4o

使用视图绑定的 Koltin 解决方案:

binding.avatar.drawable.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(R.color.white, BlendModeCompat.SRC_ATOP)

这使用了最新版本的核心 androidx 库。


M
Manohar

我刚刚遇到了这个问题并通过替换解决了它:

android:tint="@color/yellow_800"

到以下

app:tint="@color/yellow_800"

R
Rahul Sharma

当您使用库为您执行此操作时,这非常简单。试试这个library

你可以这样调用:

Icon.on(holderView).color(R.color.your_color).icon(R.mipmap.your_icon).put();