Modificar el color de un androide drawable

Me gustaría poder usar el mismo dibujable para representar ambos: Icono azul y Icono rojo Como el mismo dibujable, y volver a colorear el dibujable basado en algunos valores programáticos, de modo que el usuario final podría re-tema de la interfaz.

¿Cuál es la mejor manera de hacer esto? He intentado (y reutilizado los iconos de) esta anterior pregunta SO, pero no puedo representar el cambio como un simple cambio de tonalidad, ya que también varía en la saturación y el valor ..

¿Es mejor guardar el icono como todo blanco en el área que quiero cambiar? O transparente? O algún otro color sólido?

¿Hay algún método que le permite calcular la matriz basada en la diferencia entre Color de red_icon y Color de blue_icon?

5 Solutions collect form web for “Modificar el color de un androide drawable”

Así que después de un montón de ensayo y error, la lectura de diferentes artículos, y lo más importante, pasando por la API Demos (ColorFilters.java – que se encuentra en com.example.android.apis.graphics) encontré la solución.

Para las imágenes sólidas, he encontrado que es mejor utilizar el filtro de color PorterDuff.Mode.SRC_ATOP, ya que superpondrá el color en la parte superior de la imagen de origen, lo que le permite cambiar el color al color exacto que está buscando.

Para imágenes que son más complejas, como la anterior, he encontrado que lo mejor es colorear toda la imagen BLANCA (FFFFFF) para que cuando hagas PorterDuff.Mode.MULTIPLY, acabes con los colores correctos y Todo el negro (000000) de la imagen permanecerá negro.

El colorfilters.java le muestra cómo se hace si su dibujo en un lienzo, pero si todo lo que necesita es un color dibujable entonces esto funcionará:

COLOR2 = Color.parseColor("#FF"+getColor()); Mode mMode = Mode.SRC_ATOP; Drawable d = mCtx.getResources().getDrawable(R.drawable.image); d.setColorFilter(COLOR2,mMode) 

Creé una actividad de demostración utilizando parte del código de demostración API para intercambiar entre todos los modos de filtro de color para probarlos en diferentes situaciones y lo he encontrado invaluable, por lo que pensé publicarlo aquí.

 public class ColorFilters extends GraphicsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private Activity mActivity; private Drawable mDrawable; private Drawable[] mDrawables; private Paint mPaint; private Paint mPaint2; private float mPaintTextOffset; private int[] mColors; private PorterDuff.Mode[] mModes; private int mModeIndex; private Typeface futura_bold; private AssetManager assets; private static void addToTheRight(Drawable curr, Drawable prev) { Rect r = prev.getBounds(); int x = r.right + 12; int center = (r.top + r.bottom) >> 1; int h = curr.getIntrinsicHeight(); int y = center - (h >> 1); curr.setBounds(x, y, x + curr.getIntrinsicWidth(), y + h); } public SampleView(Activity activity) { super(activity); mActivity = activity; Context context = activity; setFocusable(true); /**1. GET DRAWABLE, SET BOUNDS */ assets = context.getAssets(); mDrawable = context.getResources().getDrawable(R.drawable.roundrect_gray_button_bg_nine); mDrawable.setBounds(0, 0, mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight()); mDrawable.setDither(true); int[] resIDs = new int[] { R.drawable.roundrect_gray_button_bg, R.drawable.order_button_white, R.drawable.yellowbar }; mDrawables = new Drawable[resIDs.length]; Drawable prev = mDrawable; for (int i = 0; i < resIDs.length; i++) { mDrawables[i] = context.getResources().getDrawable(resIDs[i]); mDrawables[i].setDither(true); addToTheRight(mDrawables[i], prev); prev = mDrawables[i]; } /**2. SET Paint for writing text on buttons */ mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setTextSize(16); mPaint.setTextAlign(Paint.Align.CENTER); mPaint2 = new Paint(mPaint); /** Calculating size based on font */ futura_bold = Typeface.createFromAsset(assets, "fonts/futurastd-bold.otf"); //Determine size and offset to write text in label based on font size. mPaint.setTypeface(futura_bold); Paint.FontMetrics fm = mPaint.getFontMetrics(); mPaintTextOffset = (fm.descent + fm.ascent) * 0.5f; mColors = new int[] { 0, 0xFFA60017,//WE USE THESE 0xFFC6D405, 0xFF4B5B98, 0xFF656565, 0xFF8888FF, 0xFF4444FF, }; mModes = new PorterDuff.Mode[] { PorterDuff.Mode.DARKEN, PorterDuff.Mode.DST, PorterDuff.Mode.DST_ATOP, PorterDuff.Mode.DST_IN, PorterDuff.Mode.DST_OUT, PorterDuff.Mode.DST_OVER, PorterDuff.Mode.LIGHTEN, PorterDuff.Mode.MULTIPLY, PorterDuff.Mode.SCREEN, PorterDuff.Mode.SRC, PorterDuff.Mode.SRC_ATOP, PorterDuff.Mode.SRC_IN, PorterDuff.Mode.SRC_OUT, PorterDuff.Mode.SRC_OVER, PorterDuff.Mode.XOR }; mModeIndex = 0; updateTitle(); } private void swapPaintColors() { if (mPaint.getColor() == 0xFF000000) { mPaint.setColor(0xFFFFFFFF); mPaint2.setColor(0xFF000000); } else { mPaint.setColor(0xFF000000); mPaint2.setColor(0xFFFFFFFF); } mPaint2.setAlpha(0); } private void updateTitle() { mActivity.setTitle(mModes[mModeIndex].toString()); } private void drawSample(Canvas canvas, ColorFilter filter) { /** Create a rect around bounds, ensure size offset */ Rect r = mDrawable.getBounds(); float x = (r.left + r.right) * 0.5f; float y = (r.top + r.bottom) * 0.5f - mPaintTextOffset; /**Set color filter to selected color * create canvas (filled with this color) * Write text using paint (new color) */ mDrawable.setColorFilter(filter); mDrawable.draw(canvas); /** If the text doesn't fit in the button, make the text size smaller until it does*/ final float size = mPaint.measureText("Label"); if((int) size > (r.right-r.left)) { float ts = mPaint.getTextSize(); Log.w("DEBUG","Text size was"+ts); mPaint.setTextSize(ts-2); } canvas.drawText("Sausage Burrito", x, y, mPaint); /** Write the text and draw it onto the drawable*/ for (Drawable dr : mDrawables) { dr.setColorFilter(filter); dr.draw(canvas); } } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(0xFFCCCCCC); canvas.translate(8, 12); for (int color : mColors) { ColorFilter filter; if (color == 0) { filter = null; } else { filter = new PorterDuffColorFilter(color, mModes[mModeIndex]); } drawSample(canvas, filter); canvas.translate(0, 55); } } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: // update mode every other time we change paint colors if (mPaint.getColor() == 0xFFFFFFFF) { mModeIndex = (mModeIndex + 1) % mModes.length; updateTitle(); } swapPaintColors(); invalidate(); break; } return true; } } } 

Las otras dos dependencias, GraphicsActivity.java y PictureLayout.java, se pueden copiar directamente de la actividad API Demos si desea probarla.

Esto es realmente fácil de hacer en Lollipop. Hacer un xml dibujable y hacer referencia a su png y establecer el tinte de esta manera:

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

Echa un vistazo a mi blog para obtener más información .

Su respuesta es muy agradable. Aunque, esta solución es la práctica también si está utilizando una Textview y un embed dibujable:

 int colorARGB = R.color.your_color; Drawable[] textviewDrawables = drawerItem.getCompoundDrawables(); // Left Drawable textviewDrawables[0].setColorFilter(colorARGB, PorterDuff.Mode.SRC_ATOP); 

En caso de que si desea aplicar el filtro de color a su imagen en ImageView puede implementar incluso de manera más fácil. Simplemente utilice el atributo android:tint en ImageView en xml.

Ejemplo:

 <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/your_drawable" android:tint="@color/your_color" /> 

Probado en Android 4.1.2 y 6.0.1

Aquí hay algo mejor, IMHO, que la respuesta aceptada. Se deriva de este subproceso StackOverflow: Comprender el uso de ColorMatrix y ColorMatrixColorFilter para modificar la tonalidad de un Drawable

Ejemplo de uso:

 ImageView imageView = ...; Drawable drawable = imageView.getDrawable(); ColorFilter colorFilter = ColorFilterGenerator.from(drawable).to(Color.RED); imageView.setColorFilter(colorFilter); 

Copie la clase en su proyecto:

 import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.PictureDrawable; import android.widget.ImageView; /** * Creates a {@link ColorMatrixColorFilter} to adjust the hue, saturation, brightness, or * contrast of an {@link Bitmap}, {@link Drawable}, or {@link ImageView}. * <p/> * Example usage: * <br/> * {@code imageView.setColorFilter(ColorFilterGenerator.from(Color.BLUE).to(Color.RED));} * * @author Jared Rummler <jared.rummler@gmail.com> */ public class ColorFilterGenerator { // Based off answer from StackOverflow // See: https://stackoverflow.com/a/15119089/1048340 private ColorFilterGenerator() { throw new AssertionError(); } public static From from(Drawable drawable) { return new From(drawableToBitmap(drawable)); } public static From from(Bitmap bitmap) { return new From(bitmap); } public static From from(int color) { return new From(color); } // -------------------------------------------------------------------------------------------- private static final double DELTA_INDEX[] = { 0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11, 0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24, 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42, 0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68, 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98, 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54, 1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25, 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0, 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8, 10.0 }; public static void adjustHue(ColorMatrix cm, float value) { value = cleanValue(value, 180f) / 180f * (float) Math.PI; if (value == 0) { return; } float cosVal = (float) Math.cos(value); float sinVal = (float) Math.sin(value); float lumR = 0.213f; float lumG = 0.715f; float lumB = 0.072f; float[] mat = new float[]{ lumR + cosVal * (1 - lumR) + sinVal * (-lumR), lumG + cosVal * (-lumG) + sinVal * (-lumG), lumB + cosVal * (-lumB) + sinVal * (1 - lumB), 0, 0, lumR + cosVal * (-lumR) + sinVal * (0.143f), lumG + cosVal * (1 - lumG) + sinVal * (0.140f), lumB + cosVal * (-lumB) + sinVal * (-0.283f), 0, 0, lumR + cosVal * (-lumR) + sinVal * (-(1 - lumR)), lumG + cosVal * (-lumG) + sinVal * (lumG), lumB + cosVal * (1 - lumB) + sinVal * (lumB), 0, 0, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 0f, 1f }; cm.postConcat(new ColorMatrix(mat)); } public static void adjustBrightness(ColorMatrix cm, float value) { value = cleanValue(value, 100); if (value == 0) { return; } float[] mat = new float[]{ 1, 0, 0, 0, value, 0, 1, 0, 0, value, 0, 0, 1, 0, value, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 }; cm.postConcat(new ColorMatrix(mat)); } public static void adjustContrast(ColorMatrix cm, int value) { value = (int) cleanValue(value, 100); if (value == 0) { return; } float x; if (value < 0) { x = 127 + value / 100 * 127; } else { x = value % 1; if (x == 0) { x = (float) DELTA_INDEX[value]; } else { x = (float) DELTA_INDEX[(value << 0)] * (1 - x) + (float) DELTA_INDEX[(value << 0) + 1] * x; } x = x * 127 + 127; } float[] mat = new float[]{ x / 127, 0, 0, 0, 0.5f * (127 - x), 0, x / 127, 0, 0, 0.5f * (127 - x), 0, 0, x / 127, 0, 0.5f * (127 - x), 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 }; cm.postConcat(new ColorMatrix(mat)); } public static void adjustSaturation(ColorMatrix cm, float value) { value = cleanValue(value, 100); if (value == 0) { return; } float x = 1 + ((value > 0) ? 3 * value / 100 : value / 100); float lumR = 0.3086f; float lumG = 0.6094f; float lumB = 0.0820f; float[] mat = new float[]{ lumR * (1 - x) + x, lumG * (1 - x), lumB * (1 - x), 0, 0, lumR * (1 - x), lumG * (1 - x) + x, lumB * (1 - x), 0, 0, lumR * (1 - x), lumG * (1 - x), lumB * (1 - x) + x, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 }; cm.postConcat(new ColorMatrix(mat)); } // -------------------------------------------------------------------------------------------- private static float cleanValue(float p_val, float p_limit) { return Math.min(p_limit, Math.max(-p_limit, p_val)); } private static float[] getHsv(int color) { float[] hsv = new float[3]; Color.RGBToHSV(Color.red(color), Color.green(color), Color.blue(color), hsv); return hsv; } /** * Converts a {@link Drawable} to a {@link Bitmap} * * @param drawable * The {@link Drawable} to convert * @return The converted {@link Bitmap}. */ private static Bitmap drawableToBitmap(Drawable drawable) { if (drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); } else if (drawable instanceof PictureDrawable) { PictureDrawable pictureDrawable = (PictureDrawable) drawable; Bitmap bitmap = Bitmap.createBitmap(pictureDrawable.getIntrinsicWidth(), pictureDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); canvas.drawPicture(pictureDrawable.getPicture()); return bitmap; } int width = drawable.getIntrinsicWidth(); width = width > 0 ? width : 1; int height = drawable.getIntrinsicHeight(); height = height > 0 ? height : 1; Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); return bitmap; } /** * Calculate the average red, green, blue color values of a bitmap * * @param bitmap * a {@link Bitmap} * @return */ private static int[] getAverageColorRGB(Bitmap bitmap) { int width = bitmap.getWidth(); int height = bitmap.getHeight(); int size = width * height; int[] pixels = new int[size]; int r, g, b; r = g = b = 0; bitmap.getPixels(pixels, 0, width, 0, 0, width, height); for (int i = 0; i < size; i++) { int pixelColor = pixels[i]; if (pixelColor == Color.TRANSPARENT) { size--; continue; } r += Color.red(pixelColor); g += Color.green(pixelColor); b += Color.blue(pixelColor); } r /= size; g /= size; b /= size; return new int[]{ r, g, b }; } /** * Calculate the average color value of a bitmap * * @param bitmap * a {@link Bitmap} * @return */ private static int getAverageColor(Bitmap bitmap) { int[] rgb = getAverageColorRGB(bitmap); return Color.argb(255, rgb[0], rgb[1], rgb[2]); } // Builder // -------------------------------------------------------------------------------------------- public static final class Builder { int hue; int contrast; int brightness; int saturation; public Builder setHue(int hue) { this.hue = hue; return this; } public Builder setContrast(int contrast) { this.contrast = contrast; return this; } public Builder setBrightness(int brightness) { this.brightness = brightness; return this; } public Builder setSaturation(int saturation) { this.saturation = saturation; return this; } public ColorFilter build() { ColorMatrix cm = new ColorMatrix(); adjustHue(cm, hue); adjustContrast(cm, contrast); adjustBrightness(cm, brightness); adjustSaturation(cm, saturation); return new ColorMatrixColorFilter(cm); } } public static final class From { final int oldColor; private From(Bitmap bitmap) { oldColor = getAverageColor(bitmap); } private From(int oldColor) { this.oldColor = oldColor; } public ColorFilter to(int newColor) { float[] hsv1 = getHsv(oldColor); float[] hsv2 = getHsv(newColor); int hue = (int) (hsv2[0] - hsv1[0]); int saturation = (int) (hsv2[1] - hsv1[1]); int brightness = (int) (hsv2[2] - hsv1[2]); return new ColorFilterGenerator.Builder() .setHue(hue) .setSaturation(saturation) .setBrightness(brightness) .build(); } } } 
  • Establecer dinámicamente el color del tema
  • Android: Cómo cambiar los atributos del tema dinámicamente en tiempo de ejecución de código
  • App: el tema ya está obsoleto. Pase por usar android: tema en su lugar
  • ¿Cómo agregar atributos de varios temas a la misma actividad en el manifiesto de Android?
  • Diseño de widget Android - fondo negro predeterminado
  • Cómo cambiar el estilo de pestaña en Android?
  • La barra de acción se ve cortada mientras se utiliza Theme.AppCompat.Dialog
  • Android: Utilizar colores de resaltado predeterminados en un botón personalizado
  • Utiliza el tema de Holo en la aplicación Android de Qt
  • Temas de Android: Defina colores / degradados en "baseTheme.xml", use dentro de controles, reemplace en "subThemeX.xml"
  • Error al agregar tema personalizado a la aplicación
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.