Android'de bir Drawable renkleri nasıl değiştirilir?


271

Bir android uygulaması üzerinde çalışıyorum ve bir kaynak görüntüden yüklediğim bir çekmecem var. Bu görüntüde, beyaz piksellerin tümünü farklı bir renge dönüştürmek istiyorum, mavi deyin ve daha sonra kullanabileceğim sonuçtaki Drawable nesnesini önbelleğe almak istiyorum.

Örneğin, ortasında beyaz bir daire bulunan ve dairenin dışındaki her şeyin şeffaf olduğunu belirten bir 20x20 PNG dosyam olduğunu varsayalım. Beyaz daireyi maviye çevirmenin ve sonuçları önbelleğe almanın en iyi yolu nedir? Birkaç yeni Çizilebilir Çizim (örneğin mavi, kırmızı, yeşil, turuncu, vb.) Oluşturmak için bu kaynak görüntüyü kullanmak istersem cevap değişir mi?

Bir şekilde bir ColorMatrix kullanmak isteyeceğimi tahmin ediyorum, ama nasıl yapılacağından emin değilim.


2
Sonunda bunu bir şekilde yaptın mı? Aşağıda pek çok cevap denediğim birçok cevap görüyorum ama hiçbir şey işe yaramıyor. Şu anda ihtiyaca göre her seferinde farklı renklendirmek istediğim beyaz bir karem var, böylece statik varlıklar oluşturmak zorunda değilim. Pls, hala tam beyaz renkte basit şeklim için çalışan bir çözüm bekliyorum.
omkar.ghaisas

@ omkar.ghaisas SillyAndroid adında çok yönlü bir Boyama sınıfı içeren ve çizilebilir metinler için her türlü renklendirme yapan bir kütüphane kurdum. Bunu github.com/milosmns/silly-android adresinden kontrol edebilirsiniz . Sınıf bulunur/sillyandroid/src/main/java/me/angrybyte/sillyandroid/extras/Coloring.java
milosmns

Yanıtlar:


221

Bence sadece kullanabilirsiniz Drawable.setColorFilter( 0xffff0000, Mode.MULTIPLY ). Bu, beyaz pikselleri kırmızıya ayarlar, ancak saydam pikselleri etkileyeceğini düşünmüyorum.

Bkz. Çekilebilir # setColorFilter


9
Bu, çekilebilir tek renk olduğunda iyi çalışacaktır, beyaz olduğunda daha iyi olacaktır.
Mitul Nakum

67
Renk dinamik olarak değiştirilirse (örneğin, Adaptörde) çekilebilir değiştirilebilir olmalıdır. Örnek: Drawable.mutate().setColorFilter( 0xffff0000, Mode.MULTIPLY)daha fazla bilgi: curious-creature.org/2009/05/02/drawable-mutations
sabadow

1
Evet, özellikle vurgulamak için iyidir (daha açık, daha koyu veya gri tonlamalı bir görüntüye renk tonu eklemek için) Bu hileyi, "işaretlenmemiş" öğenin gri tonlamalı ve "işaretli" uygulamamın renk paletinden kalın bir renk olduğu düğmeler arasında geçiş yapmak için kullanıyorum. Şahsen özel bir onay kutusundan daha kolay buluyorum.
thom_nic

2
Bu tam olarak aradığım şeydi, ancak bunu XML'de yapamayız inanılmaz derecede sinir bozucu ( 5.0+ hariç ). Renklendirme AppCompat'ta bile mevcut değildir, bu nedenle setColorFiltersimgeleri her kullandığımızda farklı renk tonlarına sahip seçiciler yerine aramak zorunda kaldık. Yine de, doğrudan png'leri düzenlemek ve ekstra statik varlıklara sahip olmaktan çok daha iyi bir çözümdür.
Chris Cirefice

21
Kaynak simgeniz koyu bir renkteyse çarpma çalışmaz. Kaynak simgesi şeklini hedef renkle boyamak için SRC_IN: myImage.getDrawable().mutate().setColorFilter(getResources().getColor(R.color.icon_grey), PorterDuff.Mode.SRC_IN);
Distwo

152

Bu kodu deneyin:

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

106

Bu sorunun Lollipop'tan önce sormak olduğunu biliyorum, ancak Android 5. + 'da bunu yapmak için güzel bir yol eklemek istiyorum. Orijinaline referans veren bir xml çizilebilir yaparsınız ve üzerine renk tonu ayarlarsınız:

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

bu en son destek kütüphanesinin parçası mı?
S-K '

Hayır. Bu sadece birkaç basit widget ile yardımcı olur.
MinceMan

8
Renk Tonu DrawableCompat aracılığıyla support-v4'te
Mark Renouf

1
Cool Bunu inceleyip buna göre güncelleyeceğim.
MinceMan

Fresco bu tür
çekmeceleri

62

Yeni destek v4 renk tonunu api 4'e geri getiriyor.

böyle yapabilirsin

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

2
Destek kütüphanesinden başlayarak 22.
rnrneverdies

1
Bu tercih edilen çözümdür, lolipop bırakıldığından beri renklendirilebilir çekmeceler eski API'lerde gri bir alan olmuştur. Bu bariyeri frenliyor! Bunu bilmiyordum - teşekkürler @Pei
RicardoSousaDev

2
Dikkatli ol! Durumla ilgili sorunlardan kaçınmak için yeni sarılı çekilebilir "#mutate ()" öğenizi değiştirmelisiniz. Bkz. Stackoverflow.com/a/44593641/5555218
Ricard

62

Düz renkte olan bir çekmeceniz varsa ve onu difernet düz renk olarak değiştirmek istiyorsanız, bir ColorMatrixColorFilter. Şeffaflık korunur.

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
Bir dize (# ff0000 vb.) Yerine bir renk kaynağı kullanmak istiyorsanız, örneğin int iColor = getResources (). GetColor (R.color.primary)
Ben Clayton

Bu işe yarıyor ama onay kutum var ve ortadaki beyaz onay işaretini korumak istiyorum. Bunun için bir öneriniz var mı?
Farooq,

3
Ben'in yorumundaki kod artık kullanımdan kaldırıldı. Bunun yerine kullanabilirsiniz int iColor = ContextCompat.getColor(context, R.color.primary);.
ban-geoengineering

parlak cevap !! Hepinize teşekkürler!
Kaveesh Kanwal

@Mike Hill Tamam, neden 20'den fazla renk koyduğunuzu açıklayın. Diziye daha büyük sonra yirmi renk eklemeniz gerekir, çünkü java.lang.ArrayIndexOutOfBoundsException
AlexPad

50

ImageViewSimgeleri de kullanıyorum ( ListViewayarlar ekranında veya). Ama bence bunu yapmanın çok daha basit bir yolu var.

tintSeçtiğiniz simgenin renk katmanını değiştirmek için kullanın .

Xml biçiminde,

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

geldiği için iyi çalışıyor AppCompat


3
Tıkır tıkır çalışıyor! Basit ve mükemmel. Bunun kabul edilen cevap olarak işaretlenmesi gerekir.
Naga Mallesh Maddali

2
Burada birçok iyi cevap var, ancak OP'nin sorusu için bu en iyi ve en basit çözüm.
Sebastian Breit

api 22 ve üstü için
philip oghenerobo balogun

1
@philipoghenerobobalogun api 19 üzerinde bu çalışma gördüm
Jemshit Iskenderov

41

Bunu tüm API'lar için yapmanız gerekir:

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

Bu, sorunu kabul edilebilir bir şekilde çözdü. Ancak rengi filtrelerken, ortaya çıkan rengin beklendiği gibi olmadığı (benim başıma geldi) olabilir. Aydınlatılacak renk. Ne yaptım: `` yeni LightingColorFilter (Color.parseColor ("# FF000000"), myFinalColor) `
Yoraco Gonzales

1
Önceki yorumcunun söylediklerini vurgulayarak, LightingColorFilter içindeki 2 parametre farklıysa, bu çözüm renkleri ColorFilter filter = new LightingColorFilter(Color.BLACK, Color.LTGRAY);değiştirir , örneğin, çekilebilirde siyahtan griye değişecektir.
hBrent

1
Renk tonu için alfa kullanıldığında bu çalışmaz.
ypresto

30

Bunu bir etkinlikten alınan aşağıdaki kodla yapabildim (mizanpaj çok basit bir görüntü, sadece bir ImageView içeren ve burada gönderilmez).

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

Eşik veya FROM_COLOR'u nereden alabilirim?
mikepenz

Bunlar sadece tanımladığım sabitlerdi; Cevabı az önce ben de ekledim.
Matt McMinn

teşekkür ederim;) denedim ama sahip olduğum soruna uymuyor. setColorFilter'ı denedim ve bu işe yarıyor, ancak .9.png görüntüsünü ölçeklendirme ile ilgili bir sorun var. bu yüzden neden bir fikriniz varsa, lütfen soruma cevap verin. stackoverflow.com/questions/5884481/…
mikepenz

1
Renk filtreleri çok daha kolaydır.
afollestad

17

Android destek uyumluluk kütüphanelerini kullanarak çözebilirsiniz. :)

 // 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 Cevabımı neden tamamen yanlış değiştiriyorsunuz? Parça parça. 1. getResources (). GetDrawable () kullanımdan kaldırıldı !! 2. Andorid Api sürümleri ile ilgilenmek istemediğim için destek kütüphaneleri kullanıyorum. 3. Drawable'ı yeniden çizmek istemiyorum .... Başka bir yaklaşım göstermek istiyorsanız kendi cevabınızı yazın.
Ricard

1
@AmitabhaBiswas Ayrıca, çekilebilirler kaynaklardan tüm getDrawable'lar arasında paylaşılır, bu nedenle mutate()çağrının söz konusu kaynak kimliğiyle ilişkili tüm çekilebilir ortakları değiştirmeden çekilebilir bir renk tonunu değiştirebilmesi gerekir.
Ricard

1
Bu en iyi cevap! Bir görüntü görünümünde çizilebilir kaydırmak soruyu çözmez.
Julius

15

Etkinliğinizde PNG görüntü kaynaklarınızı tek bir renkle renklendirebilirsiniz:

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

Şimdi R.drawable'ı kullandığınızda. * İstenen renk tonu ile renklendirilmelidir. Ek renklere ihtiyacınız varsa, çekilebilir .mutate () yapabilmeniz gerekir.



4

Çekilebilir görüntünüzü ImageView olarak ayarladıysanız, 1 astarla yapabilirsiniz:

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

3

" ColorMatrixSample.java " örnek kodunu inceleyin

/*
 * 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();
        }
    }
}

Alakalı API'yı burada bulabilirsiniz :


1
Bu ColorMatrix'in nasıl kullanılacağını gösterir, ancak aradığım sonuçları almak için nasıl kullanılacağını göremiyorum.
Matt McMinn

3

Bu, arka plana sahip her şeyle çalışır:

Metin Görünümü, Düğme ...

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

3

Bu kod pasajı benim için çalıştı:

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

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

2

Çok fazla çözüm var ama renk kaynağı xml dosyasının zaten rengi varsa kimse önermedi, o zaman doğrudan oradan da aşağıdaki gibi seçim yapabiliriz:

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

1

Çekilebilir rengi isWorkingalana göre değiştirmek için kısa bir örnek .

Benim şekil 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>

Değiştirme yöntemim:

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

Kullanım örneği:

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 içinde

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

Java Kodu

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

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

0

Çok geç ama birinin ihtiyacı olması halinde:

   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

Bazı basit çekmeceler için çalışır. Yuvarlatılmış köşeleri olan basit bir düz renk rektifi üzerinde kullandım ve bu rengi farklı düzenlerle değiştirmek gerekiyordu.

Bunu dene

android:backgroundTint="#101010"

-1

Bunu yapmak için bir kütüphane kullandığınızda çok basittir. Bu kütüphaneyi deneyin

Bu şekilde arayabilirsiniz:

Icon.on(holderView).color(R.color.your_color).icon(R.mipmap.your_icon).put();
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.