Android에서 Drawable의 색상을 변경하는 방법은 무엇입니까?


271

나는 안드로이드 응용 프로그램에서 작업하고 있으며 소스 이미지에서로드하는 드로어 블을 가지고 있습니다. 이 이미지에서는 모든 흰색 픽셀을 파란색과 같은 다른 색상으로 변환 한 다음 결과 Drawable 객체를 캐시하여 나중에 사용할 수 있도록하고 싶습니다.

예를 들어 중간에 흰색 원이있는 20x20 PNG 파일이 있고 원 외부의 모든 것이 투명하다고 가정합니다. 흰색 원을 파란색으로 바꾸고 결과를 캐시하는 가장 좋은 방법은 무엇입니까? 소스 이미지를 사용하여 여러 개의 새로운 Drawables (예 : 파랑, 빨강, 녹색, 주황색 등)를 만들려는 경우 답변이 변경됩니까?

어떤 식 으로든 ColorMatrix를 사용하고 싶다고 생각하지만 어떻게 해야할지 모르겠습니다.


2
마침내 어떤 식 으로든 작동하게 되었습니까? 아래에서 많은 답변을 보았지만 그중에서도 많은 시도를했지만 아무것도 작동하지 않습니다. 현재 흰색 사각형이 있는데, 필요에 따라 매번 다른 색을 지정하여 정적 자산을 만들 필요가 없습니다. Pls는 여전히 단순한 흰색 모양의 작업 솔루션을 기다리고 있기 때문에 제안합니다.
omkar.ghaisas

@ omkar.ghaisas 나는 다양한 Coloring 클래스를 포함하고 Drawables 및 텍스트에 대해 모든 종류의 채색을 수행하는 SillyAndroid라는 라이브러리를 만들었습니다. github.com/milosmns/silly-android 에서 확인할 수 있습니다 . 수업은/sillyandroid/src/main/java/me/angrybyte/sillyandroid/extras/Coloring.java
milosmns

답변:


221

실제로 사용할 수 있다고 생각합니다 Drawable.setColorFilter( 0xffff0000, Mode.MULTIPLY ). 이것은 흰색 픽셀을 빨간색으로 설정하지만 투명 픽셀에 영향을 줄 것이라고 생각하지 않습니다.

Drawable # 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를 직접 편집하고 추가 정적 자산을 갖는 것보다 훨씬 나은 솔루션입니다.
Chris Cirefice

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

이 최신 지원 라이브러리의 일부입니까?
'

아니요. 몇 가지 간단한 위젯에서만 도움이됩니다.
MinceMan

8
색조 DrawableCompat를 통해 지원-V4에
마크 Renouf

1
쿨 나는 그것을 조사하고 그에 따라 이것을 업데이트합니다.
MinceMan

Fresco는 이러한 종류의 드로어 블을 지원하지 않습니다
jackqack

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 2016 년

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)
Ben Clayton

이것은 작동하지만 확인란이 있고 중간에 흰색 눈금을 유지하고 싶습니다. 그것에 대한 제안?
Farooq가

3
Ben의 의견에있는 코드는 이제 더 이상 사용되지 않습니다. 대신을 사용할 수 있습니다 int iColor = ContextCompat.getColor(context, R.color.primary);.
금지 지오 엔지니어링

훌륭한 답변 !! 모두 감사합니다!
Kaveesh Kanwal

당신이 20 개 이상을 넣어 이유 힐 좋아 @ 마이크, 그것은 java.lang.ArrayIndexOutOfBoundsException와 충돌 다른 있기 때문에 colors.You 배열에서 다음 스무 색상을 greather 삽입 할 필요가 설명
AlexPad

50

ImageView아이콘 ( ListView또는 설정 화면) 에도 사용 합니다 . 그러나 나는 그것을하는 훨씬 간단한 방법이 있다고 생각합니다.

tint선택한 아이콘의 색상 오버레이를 변경하는 데 사용 합니다.

xml에서

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

그것에서 온 이후 잘 작동합니다 AppCompat


3
매력처럼 작동합니다! 간단하고 완벽합니다. 허용 된 답변으로 표시해야합니다.
Naga Mallesh Maddali

2
여기에는 좋은 답변이 많이 있지만 OP의 질문에 대해서는 이것이 가장 좋고 가장 간단한 해결책입니다.
Sebastian Breit


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

이를 통해 문제를 수용 가능한 방식으로 해결했습니다. 그러나 색상을 필터링 할 때 결과 색상이 예상과 다르게 나타날 수 있습니다. 밝아 질 색. 내가 한 일 :`new 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

그것들은 내가 정의한 상수 일뿐입니다. 방금 포함하도록 답변을 편집했습니다.
Matt McMinn

고마워요;) 시도했지만 문제가 맞지 않습니다. setColorFilter를 시도했지만 작동하지만 .9.png 이미지의 크기를 조정하는 데 문제가 있습니다. 그 이유를 알고 있다면 내 질문에 대답하십시오. stackoverflow.com/questions/5884481/…
mikepenz

1
컬러 필터가 훨씬 쉽습니다.
afollestad

17

Android 지원 compat 라이브러리를 사용하여 해결할 수 있습니다. :)

 // 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. Drawable ...을 다시 작성하고 싶지 않습니다. 다른 접근법을 보여주고 싶다면 자신의 답변을 작성하십시오.
Ricard

1
@AmitabhaBiswas 또한 드로어 블은 리소스에서 모든 getDrawable간에 공유되므로 mutate()해당 드로어 블을 해당 리소스 ID와 관련된 모든 드로어 블을 변경하지 않고 드로어 블의 색조를 변경할 수 있어야합니다.
Ricard

1
이것이 가장 좋은 대답입니다! 이미지보기에서 드로어 블을 래핑해도 문제가 해결되지 않습니다.
Julius

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.drawable. *을 사용할 때 원하는 색조로 채색되어야합니다. 추가 색상이 필요한 경우 드로어 블을 .mutate () 할 수 있어야합니다.



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> 

자바 코드

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

간단한 드로어 블에서 작동합니다. 둥근 모서리가있는 단순한 단색 rect 모양에 사용했으며 다른 레이아웃으로 해당 색상을 변경해야했습니다.

이 시도

android:backgroundTint="#101010"

-1

라이브러리를 사용하여 그렇게 할 때 매우 간단합니다. 이 라이브러리를 사용해보십시오

다음과 같이 전화 할 수 있습니다.

Icon.on(holderView).color(R.color.your_color).icon(R.mipmap.your_icon).put();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.