Définir la couleur de la forme Android par programmation


168

J'édite pour rendre la question plus simple, en espérant que cela aide à une réponse précise.

Disons que j'ai la ovalforme suivante :

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

Comment définir la couleur par programmation, à partir d'une classe d'activités?


À quoi définissez-vous ce dessin?
Vikram

Le dessinable est un ovalet est l'arrière-plan d'un ImageView.
Cote Mounyo

Si cette question posée est trop difficile, existe-t-il un moyen de dessiner plusieurs images sur une toile et de définir le produit final en couches comme arrière-plan d'une vue?
Cote Mounyo

Vous pouvez y parvenir en étendant la Viewclasse et en l'utilisant comme basevue dans une mise en page qui permet le chevauchement des widgets ( RelativeLayout, FrameLayout). Dans cette Viewclasse étendue , vous pouvez draw multiple images onto a canvas. Mais avant de faire cela, jetez un œil à ceci -> Lien (si vous ne l'avez pas déjà fait).
Vikram

Réponses:


266

Remarque : La réponse a été mise à jour pour couvrir le scénario oùbackground trouve une instance de ColorDrawable. Merci Tyler Pfaff , de l'avoir signalé.

Le dessinable est un ovale et est l'arrière-plan d'un ImageView

Obtenez le DrawabledeimageView utilisation getBackground():

Drawable background = imageView.getBackground();

Vérifiez contre les suspects habituels:

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

Version compacte:

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

Notez que la vérification des valeurs nulles n'est pas requise.

Cependant, vous devez utiliser mutate()sur les drawables avant de les modifier s'ils sont utilisés ailleurs. (Par défaut, les dessinables chargés à partir de XML partagent le même état.)


3
Merci de répondre. (+1). Mon code connaît d'autres bogues, il est donc difficile à tester. Mais cela pourrait encore définir la solidpartie de la forme. Et la strokeportion?
Cote Mounyo

1
@TiGer Vous devez ajouter @usernamevotre commentaire pour vous assurer qu'une notification est envoyée à l'utilisateur. À propos, vous devrez ShapeDrawablecréer une sous-classe pour définir la partie de trait. Plus d'informations ici: Lien . Regardez le commentaire car il mentionne un problème avec la réponse acceptée.
Vikram

3
android.graphics.drawable.GradientDrawable ne peut pas être casté en android.graphics.drawable.ShapeDrawable Le casting échoue sur moi
John

3
@John Si votre ImageView'sarrière-plan est défini sur a GradientDrawable, getBackground()ne renverra pas de fichier ShapeDrawable. Au lieu de cela, utilisez le GradientDrawablequi est retourné: GradientDrawable gradientDrawable = (GradientDrawable)imageView.getBackground();.... gradientDrawable.setColors(new int[] { color1, color2 });.
Vikram

2
Merci .. a sauvé mon monde.
sid_09

43

Fait comme ça:

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

1
@ user3111850 Avez-vous ajouté android:backgroundvotre xml ou même une setBackgroundactivité avant d'appeler getBackground()? Cela devrait fonctionner si vous l'aviez fait.
Lee Yi Hong le

41

Une solution plus simple de nos jours serait d'utiliser votre forme comme arrière-plan, puis de changer sa couleur par programmation via:

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

Voir PorterDuff.Mode pour les options disponibles.

MISE À JOUR (API 29):

La méthode ci-dessus est obsolète depuis l'API 29 et remplacée par la suivante:

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

Voir BlendMode pour les options disponibles.


4
La bonne est la suivante: view.getBackground().setColorFilter(Color.parseColor("#343434"), PorterDuff.Mode.SRC_ATOP);Puisqu'il peut y avoir une bordure sur le fond ou des cournes arrondies.
Berkay Turancı

1
Belle @ BerkayTurancı ma forme avait des coins arrondis. Je pourrais omettre l' getBackground()appel. Mon imageview.src contenait une forme et j'ai utilisé: imageIndicator.setColorFilter(toggleColor, PorterDuff.Mode.SRC_ATOP);toggleColorest juste un int qui a précédemment stocké le résultat de getColor ()
Someone Somewhere

1
Avoir PorterDuff.Modepour BlendModeColorFilterne compilera pas comme il se doit BlendMode. Donc, pour l'API 29, cela devrait être view.background.colorFilter = BlendModeColorFilter(Color.parseColor("#343434"), BlendMode.SRC_ATOP).
Onik

Bonne prise @Onik. J'ai mis à jour la réponse en conséquence. Je vous remercie!
Georgios le

14

Essaye ça:

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

Pour plus de détails consultez ce lien ce

espérons de l'aide.


vote pour le lien. Mais ce n'est pas la réponse à ma question.
Cote Mounyo

13

j'espère que cela aidera quelqu'un avec le même problème

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
Au départ, je ne pouvais pas faire fonctionner cela, j'ai compris que votre couleur devait être fournie comme ceci:gd.setStroke(width_px, Color.parseColor("#FF5722"));
pwnsauce

12

En développant la réponse de Vikram , si vous colorez des vues dynamiques, comme des éléments de vue recycleur, etc. Vous voudrez probablement appeler mutate () avant de définir la couleur. Si vous ne le faites pas, toutes les vues qui ont un dessin commun (c.-à-d. Un arrière-plan) verront également leur dessin modifié / coloré.

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
besoins et vérification supplémentaire et paramètre: if (background instanceof LayerDrawable) { background = ((LayerDrawable) background.mutate()).getDrawable(indexIfLayerDrawable); } if (background instanceof ShapeDrawable)[...]pour gérer les dispositions d'arrière-plans qui utilisent <layer-list ... <item ....
Johny

11

Cette question a reçu une réponse il y a quelque temps, mais elle peut être modernisée en la réécrivant en tant que fonction d'extension kotlin.

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

7

c'est la solution qui fonctionne pour moi ... l'a également écrit dans une autre question: Comment changer la couleur de la forme de manière dynamique?

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

Rien ne fonctionne pour moi, mais lorsque je règle la couleur de la teinte, cela fonctionne sur Shape Drawable

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

nécessite Android 5.0 API 21


3

Version de la fonction d'extension My Kotlin basée sur les réponses ci-dessus avec 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

Le moyen simple de remplir la forme avec le rayon est:

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

1

Peut-être suis-je trop tard, mais si vous utilisez Kotlin. Il y a un moyen comme ça

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)

Prendre plaisir....


0

Pour tous ceux qui utilisent C # Xamarin, voici une méthode basée sur l'extrait de code 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;
    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.