Establecer el color de la forma de Android mediante programación


168

Estoy editando para simplificar la pregunta, con la esperanza de que ayude a obtener una respuesta precisa.

Digamos que tengo la siguiente ovalforma:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
    <solid android:angle="270"
           android:color="#FFFF0000"/>
    <stroke android:width="3dp"
            android:color="#FFAA0055"/>
</shape>

¿Cómo configuro el color mediante programación, desde una clase de actividad?


¿A qué lo configuras?
Vikram

El dibujable es ovaly es el fondo de un ImageView.
Cote Mounyo

Si esta pregunta es demasiado difícil, ¿hay alguna forma de dibujar varias imágenes en un lienzo y establecer el producto final en capas como fondo de una vista?
Cote Mounyo

Puede lograr esto extendiendo la Viewclase y usándola como basevista en un diseño que permita la superposición de widgets ( RelativeLayout, FrameLayout). Dentro de esta Viewclase extendida , puedes draw multiple images onto a canvas. Pero, antes de hacerlo, eche un vistazo a esto -> Enlace (si aún no lo ha hecho).
Vikram

Respuestas:


266

Nota : La respuesta se ha actualizado para cubrir el escenario donde backgroundhay una instancia de ColorDrawable. Gracias Tyler Pfaff , por señalar esto.

El dibujo es un óvalo y es el fondo de un ImageView

Obtener el Drawablede imageViewusar getBackground():

Drawable background = imageView.getBackground();

Verificar con los sospechosos habituales:

if (background instanceof ShapeDrawable) {
    // cast to 'ShapeDrawable'
    ShapeDrawable shapeDrawable = (ShapeDrawable) background;
    shapeDrawable.getPaint().setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof GradientDrawable) {
    // cast to 'GradientDrawable'
    GradientDrawable gradientDrawable = (GradientDrawable) background;
    gradientDrawable.setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof ColorDrawable) {
    // alpha value may need to be set again after this call
    ColorDrawable colorDrawable = (ColorDrawable) background;
    colorDrawable.setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
}

Versión compacta:

Drawable background = imageView.getBackground();
if (background instanceof ShapeDrawable) {
    ((ShapeDrawable)background).getPaint().setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof GradientDrawable) {
    ((GradientDrawable)background).setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
} else if (background instanceof ColorDrawable) {
    ((ColorDrawable)background).setColor(ContextCompat.getColor(mContext,R.color.colorToSet));
}

Tenga en cuenta que no se requiere verificación nula.

Sin embargo, debe usar mutate()los elementos dibujables antes de modificarlos si se usan en otro lugar. (De forma predeterminada, los elementos extraíbles cargados desde XML comparten el mismo estado).


3
Gracias por responder. (+1) Mi código está experimentando otros errores, por lo que es difícil de probar. Pero aún así esto podría establecer la solidparte de la forma. ¿Qué tal la strokeporción?
Cote Mounyo

1
@TiGer Debe agregar @usernamesu comentario para asegurarse de que se envíe una notificación al usuario. Por cierto, deberás subclasificar ShapeDrawablepara establecer la parte del trazo. Más información aquí: Enlace . Mire el comentario ya que menciona un problema con la respuesta aceptada.
Vikram

3
android.graphics.drawable.GradientDrawable no se puede lanzar a android.graphics.drawable.ShapeDrawable El elenco falla en mí
John

3
@John Si su ImageView'sfondo está configurado en a GradientDrawable, getBackground()no devolverá a ShapeDrawable. En su lugar, utilice el GradientDrawableque se devuelve: GradientDrawable gradientDrawable = (GradientDrawable)imageView.getBackground();.... gradientDrawable.setColors(new int[] { color1, color2 });.
Vikram

2
Gracias ... salvó mi mundo.
sid_09

43

Hazlo así:

    ImageView imgIcon = findViewById(R.id.imgIcon);
    GradientDrawable backgroundGradient = (GradientDrawable)imgIcon.getBackground();
    backgroundGradient.setColor(getResources().getColor(R.color.yellow));

1
@ user3111850 ¿Agregaste android:backgroundtu xml o incluso setBackgrounden la actividad antes de llamar getBackground()? Debería funcionar si lo hubiera hecho.
Lee Yi Hong

41

Una solución más simple hoy en día sería usar su forma como fondo y luego cambiar su color mediante programación mediante:

view.background.setColorFilter(Color.parseColor("#343434"), PorterDuff.Mode.SRC_ATOP)

Consulte PorterDuff.Mode para ver las opciones disponibles.

ACTUALIZACIÓN (API 29):

El método anterior está en desuso desde API 29 y se reemplaza por lo siguiente:

view.background.colorFilter = BlendModeColorFilter(Color.parseColor("#343434"), BlendMode.SRC_ATOP)

Ver BlendMode para ver las opciones disponibles.


44
La correcta es: view.getBackground().setColorFilter(Color.parseColor("#343434"), PorterDuff.Mode.SRC_ATOP);ya que puede haber un borde en el fondo o correos redondeados.
Berkay Turancı

1
Nice one @ BerkayTurancı mi forma tenía esquinas redondeadas. Podría omitir la getBackground()llamada. Mi imageview.src contenía una forma y utilicé: imageIndicator.setColorFilter(toggleColor, PorterDuff.Mode.SRC_ATOP);where toggleColores solo un int que previamente almacenó el resultado de getColor ()
Someone Somewhere

1
Tener PorterDuff.Modepara BlendModeColorFilterno se compilará como se requiere BlendMode. Entonces para API 29 debería ser view.background.colorFilter = BlendModeColorFilter(Color.parseColor("#343434"), BlendMode.SRC_ATOP).
Onik

Buena captura @Onik. He actualizado la respuesta en consecuencia. ¡Gracias!
Georgios

14

Prueba esto:

 public void setGradientColors(int bottomColor, int topColor) {
 GradientDrawable gradient = new GradientDrawable(Orientation.BOTTOM_TOP, new int[]  
 {bottomColor, topColor});
 gradient.setShape(GradientDrawable.RECTANGLE);
 gradient.setCornerRadius(10.f);
 this.setBackgroundDrawable(gradient);
 }

para más detalles revise este enlace este

Espero ayuda.


arriba votar por el enlace. Pero no es la respuesta a mi pregunta.
Cote Mounyo

13

espero que esto ayude a alguien con el mismo problema

GradientDrawable gd = (GradientDrawable) YourImageView.getBackground();
//To shange the solid color
gd.setColor(yourColor)

//To change the stroke color
int width_px = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, youStrokeWidth, getResources().getDisplayMetrics());
gd.setStroke(width_px, yourColor);

1
Inicialmente no pude hacer que esto funcionara, descubrí que tu Color debe proporcionarse de esta manera:gd.setStroke(width_px, Color.parseColor("#FF5722"));
pwnsauce

12

Ampliando la respuesta de Vikram , si está coloreando vistas dinámicas, como elementos de vista de reciclador, etc. Entonces probablemente quiera llamar a mutate () antes de establecer el color. Si no hace esto, cualquier vista que tenga un dibujo común (es decir, un fondo) también cambiará / coloreará su dibujo.

public static void setBackgroundColorAndRetainShape(final int color, final Drawable background) {

    if (background instanceof ShapeDrawable) {
        ((ShapeDrawable) background.mutate()).getPaint().setColor(color);
    } else if (background instanceof GradientDrawable) {
        ((GradientDrawable) background.mutate()).setColor(color);
    } else if (background instanceof ColorDrawable) {
        ((ColorDrawable) background.mutate()).setColor(color);
    }else{
        Log.w(TAG,"Not a valid background type");
    }

}

3
necesidades y verificación adicional y parámetro: if (background instanceof LayerDrawable) { background = ((LayerDrawable) background.mutate()).getDrawable(indexIfLayerDrawable); } if (background instanceof ShapeDrawable)[...]para manejar los diseños de fondos que usan <layer-list ... <item ....
Johny

11

Esta pregunta fue respondida hace un tiempo, pero se puede modernizar reescribiendo como una función de extensión kotlin.

fun Drawable.overrideColor(@ColorInt colorInt: Int) {
    when (this) {
        is GradientDrawable -> setColor(colorInt)
        is ShapeDrawable -> paint.color = colorInt
        is ColorDrawable -> color = colorInt
    }
}

7

esta es la solución que funciona para mí ... también la escribí en otra pregunta: ¿Cómo cambiar dinámicamente el color de la forma?

//get the image button by id
ImageButton myImg = (ImageButton) findViewById(R.id.some_id);

//get drawable from image button
GradientDrawable drawable = (GradientDrawable) myImg.getDrawable();

//set color as integer
//can use Color.parseColor(color) if color is a string
drawable.setColor(color)

4

Nada funciona para mí, pero cuando configuro el color de tinte funciona en Shape Drawable

 Drawable background = imageView.getBackground();
 background.setTint(getRandomColor())

requiere Android 5.0 API 21


3

Mi versión de la función de extensión Kotlin basada en las respuestas anteriores con Compat :

fun Drawable.overrideColor_Ext(context: Context, colorInt: Int) {
    val muted = this.mutate()
    when (muted) {
        is GradientDrawable -> muted.setColor(ContextCompat.getColor(context, colorInt))
        is ShapeDrawable -> muted.paint.setColor(ContextCompat.getColor(context, colorInt))
        is ColorDrawable -> muted.setColor(ContextCompat.getColor(context, colorInt))
        else -> Log.d("Tag", "Not a valid background type")
    }
}

1

La manera simple de llenar la forma con el Radio es:

(view.getBackground()).setColorFilter(Color.parseColor("#FFDE03"), PorterDuff.Mode.SRC_IN);

1

Quizás sea demasiado tarde, pero si estás usando Kotlin. Hay una manera como esta

var gd = layoutMain.background as GradientDrawable

 //gd.setCornerRadius(10)
  gd.setColor(ContextCompat.getColor(ctx , R.color.lightblue))
  gd.setStroke(1, ContextCompat.getColor(ctx , R.color.colorPrimary)) // (Strokewidth,colorId)

Disfrutar....


0

Para cualquiera que use C # Xamarin, aquí hay un método basado en el fragmento de Vikram:

private void SetDrawableColor(Drawable drawable, Android.Graphics.Color color)
{
    switch (drawable)
    {
        case ShapeDrawable sd:
            sd.Paint.Color = color;
            break;
        case GradientDrawable gd:
            gd.SetColor(color);
            break;
        case ColorDrawable cd:
            cd.Color = color;
            break;
    }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.