Як змінити кольори рисунку в Android?


271

Я працюю над додатком для android, і у мене є малюнок, який я завантажую з вихідного зображення. На цьому зображенні я хотів би перетворити всі білі пікселі в інший колір, скажімо, синій, а потім кешувати отриманий об'єкт Dravable, щоб потім використовувати його пізніше.

Так, наприклад, скажіть, що у мене є файл PNG розміром 20x20, який має біле коло посередині, і що все поза колом прозоре. Який найкращий спосіб перетворити біле коло на синій і кешувати результати? Чи змінюється відповідь, якщо я хочу використовувати це вихідне зображення для створення декількох нових Drawables (скажімо, синього, червоного, зеленого, помаранчевого тощо)?

Я здогадуюсь, що я хочу якось використовувати ColorMatrix, але я не знаю як.


2
Ви, нарешті, так чи інакше спрацювали? Я бачу внизу багато відповідей, з яких я також спробував багато, але нічого не виходить. На даний момент у мене є білий квадрат, який я хотів би розфарбовувати кожен раз, залежно від потреби, так що мені не доведеться створювати статичні активи. Прошу запропонувати, оскільки я все ще чекаю робочого рішення для моєї простої форми в повному білому кольорі.
omkar.ghaisas

@ omkar.ghaisas Я створив бібліотеку під назвою SillyAndroid, яка містить універсальний клас «Розмальовки» та робить всілякі розмальовки для малюнків та тексту. Ви можете перевірити це на веб- сайті github.com/milosmns/silly-android . Клас знаходиться за адресою/sillyandroid/src/main/java/me/angrybyte/sillyandroid/extras/Coloring.java
milosmns

Відповіді:


221

Я думаю, що ви насправді можете просто використовувати Drawable.setColorFilter( 0xffff0000, Mode.MULTIPLY ). Це встановило б білі пікселі червоним, але я не думаю, що це вплине на прозорі пікселі.

Див. Розділ Dravable # setColorFilter


9
Це буде добре працювати, коли малювання одноколірне, краще, коли його білий.
Mitul Nakum

67
Якщо колір змінено динамічно (наприклад, у адаптері), малюнок має бути змінений. Приклад: Drawable.mutate().setColorFilter( 0xffff0000, Mode.MULTIPLY)додаткова інформація: curious-creature.org/2009/05/02/drawable-mutations
sabadow

1
Так, це особливо добре для підсвічування (світлішого, темнішого або додавання відтінку зображенню в кольорах сірого.) Я використовую цей трюк для перемикання кнопок, де "не відмічено" - відтінки сірого та "перевірено" - це сміливий колір із палітри кольорів мого додатка. Особисто мені це легше, ніж користувацький прапорець.
thom_nic

2
Це саме те, що я шукав, хоча це дуже прикро, що ми не можемо цього зробити в XML ( за винятком 5.0+ ). Тонування навіть не доступне в AppCompat, тому нам не доводиться телефонувати setColorFilterщоразу, коли ми використовуємо піктограми, а не селектори з різними кольоровими відтінками. Але це набагато краще рішення, ніж редагувати png безпосередньо та мати додаткові статичні активи.
Кріс Сірефіс

21
Множення не буде працювати, якщо значок вашого джерела має темний колір. Щоб намалювати форму піктограми джерела кольором призначення, використовуйте SRC_IN: myImage.getDrawable().mutate().setColorFilter(getResources().getColor(R.color.icon_grey), PorterDuff.Mode.SRC_IN);
Distwo

152

Спробуйте цей код:

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

106

Я знаю, що це питання було питанням до 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"/>

це частина останньої бібліотеки підтримки?
S-K '

Ні. Це допомагає лише за допомогою декількох простих віджетів.
MinceMan

8
Відтінок є підтримкою-v4 через DravableCompat
Марк

1
Класно, я роздивлюсь це і оновлю це відповідно.
MinceMan

Fresco не підтримує цей тип
малювання

62

Нова підтримка v4 поверне відтінок до api 4.

ви можете зробити це так

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

2
Починаючи з бібліотеки підтримки 22.
rnrneverdies

1
Це найкраще рішення, тонування малюнкових матеріалів було сірою зоною у старих API, з моменту виходу льодяника. Це гальмує цей бар'єр! Я не знав про це - дякую @Pei
RicardoSousaDev

2
Будь обережний! Щоб уникнути проблем, пов’язаних із станом, слід вимкнути новий завершений текст "#mutate ()". Дивіться stackoverflow.com/a/44593641/5555218
Рікард

62

Якщо у вас є малюнок, який має суцільний колір, і ви хочете змінити його на різний колір, ви можете використовувати 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);

3
Якщо ви хочете використовувати кольоровий ресурс, а не рядок (# ff0000 тощо), ви можете використовувати, наприклад, int iColor = getResources (). GetColor (R.color.primary)
Бен Клейтон

це працює, але у мене є прапорець, і я хочу зберегти білий галочку посередині. Будь-яка пропозиція щодо цього?
Фарук Аршед

3
Код у коментарі Бена тепер застарілий. Натомість можна використовувати int iColor = ContextCompat.getColor(context, R.color.primary);.
заборона-геоінженерія

блискуча відповідь !! Дякую усім!
Kaveesh Kanwal

@ Майк Хілл Добре, поясніть, чому ви вкладаєте більше 20 кольорів. Вам потрібно вставити більше, ніж двадцять кольорів у масив, тому що в іншому випадку це збій з java.lang.ArrayIndexOutOfBoundsException
AlexPad

50

Я також використовую ImageViewдля значків (вListView екрані чи налаштуваннях). Але я думаю, що існує набагато простіший спосіб зробити це.

Використовуйте tint щоб змінити кольорове накладення вибраного значка.

У xml,

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

працює чудово, оскільки вона походить AppCompat


3
Працює як шарм! Простий і ідеальний. Це потрібно позначити як прийняту відповідь.
Naga Mallesh Maddali

2
Тут є багато хороших відповідей, але на питання ОП це найкраще і найпростіше рішення.
Себастьян Брейт

для api 22 і вище
philip oghenerobo balogun

1
@philipoghenerobobalogun Я бачив це, працюючи на api 19
Jemshit Iskenderov

41

Ви повинні зробити це для всіх API:

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

Це вирішило це питання прийнятним чином. Але при фільтруванні кольору може трапитися (зі мною трапилось), що отриманий колір не такий, як очікувалося. Колір, який мав світлішати. Що я зробив: `новий LightingColorFilter (Color.parseColor (" # FF000000 "), myFinalColor)`
Yoraco Gonzales

1
Підкреслюючи те, що, на мій погляд, говорить попередній коментатор, це рішення змінює кольори, якщо два параметри в LightingColorFilter відрізняються, наприклад, ColorFilter filter = new LightingColorFilter(Color.BLACK, Color.LTGRAY);зміниться чорний на сірий у малюванні.
hBrent

1
Здається, це не працює, коли альфа використовується для кольору відтінку.
ypresto

30

Я зміг це зробити за допомогою наступного коду, який взято з діяльності (макет дуже простий, просто містить 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?
mikepenz

Це були лише константи, які я визначив; Я просто відредагував відповідь, щоб включити їх.
Метт Макмінн

дякую;) спробував, але це не відповідає тій проблемі, яку я маю. спробував setColorFilter, і це працює, але є проблема зі масштабуванням зображення .9.png. тому якщо у вас є ідея, чому, будь ласка, дайте відповідь на моє запитання. stackoverflow.com/questions/5884481 / ...
mikepenz

1
Кольорові фільтри набагато простіше.
afollestad

17

Вирішити це можна за допомогою бібліотек, що підтримують 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))

1
@AmitabhaBiswas Чому ви повністю перейшли на неправильну мою відповідь? Частина за частиною. 1. getResources (). GetDrawable () застаріло !! 2. Я використовую бібліотеки підтримки, бо не хочу перейматися версіями Andorid Api. 3. Я не хочу перемальовувати Dravable .... Якщо ви хочете показати інший підхід, напишіть власну відповідь.
Рікард

1
@AmitabhaBiswas Крім того, черпаки поділяються між усіма дістатими ресурсами, отже mutate(), потрібен дзвінок, щоб мати змогу змінити відтінок рисунка, не змінюючи всіх пов'язаних з цим ідентифікатором ресурсів.
Рікард

1
Це найкраща відповідь! Обгортання рисунка у вигляді зображення не вирішує питання.
Юлій

15

У своїй діяльності ви можете підфарбувати ресурси 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.dravable. * Його слід пофарбувати бажаним відтінком. Якщо вам потрібні додаткові кольори, тоді ви зможете мутувати () малювати.



4

Якщо у вас є графічний набір ImageView, ви можете зробити це за допомогою вкладиша 1:

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

3

Перевірте цей зразок коду " 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 доступний тут :


1
Це показує, як використовувати ColorMatrix, але я не бачу, як його використовувати, щоб отримати результати, які я шукаю.
Метт МакМінн

3

Це працює з усім із фоном:

Перегляд тексту, кнопка ...

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

3

Цей фрагмент коду працював для мене:

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

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

2

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

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

1

Короткий приклад зміни рисувального кольору відповідно до 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);

0
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);

0

Занадто пізно, але якщо комусь це потрібно:

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

0

Він працює для деяких простих малюнків. Я використав її на простій прямокутній формі прямої форми із закругленими кутами і мені потрібно було змінити цей колір за допомогою різних макетів.

Спробуйте це

android:backgroundTint="#101010"

-1

Це дуже просто, коли ви використовуєте бібліотеку, щоб зробити це для вас. Спробуйте цю бібліотеку

Ви можете зателефонувати так:

Icon.on(holderView).color(R.color.your_color).icon(R.mipmap.your_icon).put();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.