Як змінити кольори рисунку в 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.