Stellen Sie die Farbe der Android-Form programmgesteuert ein


168

Ich bearbeite, um die Frage zu vereinfachen, in der Hoffnung, dass dies zu einer genauen Antwort beiträgt.

Angenommen, ich habe die folgende ovalForm:

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

Wie stelle ich die Farbe programmgesteuert innerhalb einer Aktivitätsklasse ein?


Worauf setzen Sie diese Zeichnung?
Vikram

Das Drawable ist ein ovalund ist der Hintergrund einer ImageView.
Cote Mounyo

Wenn diese Frage zu schwierig ist, gibt es eine Möglichkeit, mehrere Bilder auf eine Leinwand zu zeichnen und das geschichtete Endprodukt als Hintergrund für eine Ansicht festzulegen?
Cote Mounyo

Sie können dies erreichen, indem Sie die ViewKlasse erweitern und als baseAnsicht in einem Layout verwenden, das das Überlappen von Widgets ( RelativeLayout, FrameLayout) ermöglicht. Innerhalb dieser erweiterten ViewKlasse können Sie draw multiple images onto a canvas. Aber bevor Sie das tun, schauen Sie sich diesen -> Link an (falls Sie es noch nicht getan haben).
Vikram

Antworten:


265

Hinweis : Die Antwort wurde aktualisiert, um das Szenario abzudecken, in dem backgroundsich eine Instanz von befindet ColorDrawable. Vielen Dank an Tyler Pfaff für diesen Hinweis.

Das Zeichenobjekt ist oval und bildet den Hintergrund einer ImageView

Holen Sie sich das Drawableaus imageViewmit getBackground():

Drawable background = imageView.getBackground();

Überprüfen Sie gegen übliche Verdächtige:

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

Kompakte Version:

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

Beachten Sie, dass keine Nullprüfung erforderlich ist.

Sie sollten mutate()die Drawables jedoch verwenden, bevor Sie sie ändern, wenn sie an anderer Stelle verwendet werden. (Standardmäßig haben aus XML geladene Drawables denselben Status.)


3
Danke für die Antwort. (+1). In meinem Code treten andere Fehler auf, daher ist das Testen schwierig. Dies könnte jedoch den solidTeil der Form bestimmen. Wie wäre es mit der strokePortion?
Cote Mounyo

1
@TiGer Sie sollten @usernameIhren Kommentar hinzufügen , um sicherzustellen, dass eine Benachrichtigung an den Benutzer gesendet wird. Übrigens müssen Sie eine Unterklasse ShapeDrawableerstellen, um den Strichanteil festzulegen. Mehr Infos hier: Link . Sehen Sie sich den Kommentar an, in dem ein Problem mit der akzeptierten Antwort erwähnt wird.
Vikram

3
android.graphics.drawable.GradientDrawable kann nicht in android.graphics.drawable.ShapeDrawable umgewandelt werden. Die Umwandlung schlägt bei mir fehl
John

3
@John Wenn Ihr ImageView'sHintergrund auf a gesetzt ist GradientDrawable, getBackground()wird a nicht zurückgegeben ShapeDrawable. Verwenden Sie stattdessen die GradientDrawabledie zurückgegeben wird: GradientDrawable gradientDrawable = (GradientDrawable)imageView.getBackground();.... gradientDrawable.setColors(new int[] { color1, color2 });.
Vikram

2
Danke .. hat meine Welt gerettet.
Sid_09

43

Mach das so:

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

1
@ user3111850 Haben Sie android:backgroundIhre XML- Datei oder sogar setBackgroundAktivitäten hinzugefügt, bevor Sie anrufen getBackground()? Es sollte funktionieren, wenn Sie dies getan hätten.
Lee Yi Hong

40

Eine einfachere Lösung wäre heutzutage, Ihre Form als Hintergrund zu verwenden und dann ihre Farbe programmgesteuert zu ändern über:

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

Die verfügbaren Optionen finden Sie unter PorterDuff.Mode .

UPDATE (API 29):

Die obige Methode ist seit API 29 veraltet und wird durch Folgendes ersetzt:

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

Die verfügbaren Optionen finden Sie unter BlendMode .


4
Richtig ist: view.getBackground().setColorFilter(Color.parseColor("#343434"), PorterDuff.Mode.SRC_ATOP);Da es im Hintergrund einen Rand oder abgerundete Courner geben kann.
Berkay Turancı

1
Schön @ BerkayTurancı meine Form hatte abgerundete Ecken. Ich könnte den getBackground()Anruf unterlassen . Meine imageview.src enthielt eine Form und ich verwendete: imageIndicator.setColorFilter(toggleColor, PorterDuff.Mode.SRC_ATOP);wo toggleColorist nur ein int, der zuvor das Ergebnis von getColor ()
Someone Somewhere

1
Haben PorterDuff.Modefür BlendModeColorFilterwird nicht kompiliert, wie es erfordert BlendMode. Für API 29 sollte es also so sein view.background.colorFilter = BlendModeColorFilter(Color.parseColor("#343434"), BlendMode.SRC_ATOP).
Onik

Guter Fang @Onik. Ich habe die Antwort entsprechend aktualisiert. Danke dir!
Georgios

14

Versuche dies:

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

Weitere Informationen finden Sie unter diesem Link dieses

hoffe hilf.


Stimmen Sie für den Link ab. Aber es ist nicht die Antwort auf meine Frage.
Cote Mounyo

13

Ich hoffe, dies hilft jemandem mit dem gleichen Problem

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
Anfangs konnte ich das nicht zum Laufen bringen , ich fand heraus, dass Ihre Farbe wie folgt bereitgestellt werden muss:gd.setStroke(width_px, Color.parseColor("#FF5722"));
pwnsauce

12

Erweitern Sie die Antwort von Vikram , wenn Sie dynamische Ansichten wie Elemente der Recycler-Ansicht usw. ausmalen. Dann möchten Sie wahrscheinlich mutate () aufrufen, bevor Sie die Farbe festlegen. Wenn Sie dies nicht tun, wird bei Ansichten mit einem gemeinsamen Zeichen (dh einem Hintergrund) auch das Zeichen geändert / farbig.

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
Bedürfnisse und zusätzliche Prüfung und Parameter: if (background instanceof LayerDrawable) { background = ((LayerDrawable) background.mutate()).getDrawable(indexIfLayerDrawable); } if (background instanceof ShapeDrawable)[...]um mit Hintergrundlayouts umzugehen, die verwendet werden <layer-list ... <item ....
Johny

11

Diese Frage wurde vor einiger Zeit beantwortet, kann aber durch Umschreiben als Kotlin-Erweiterungsfunktion modernisiert werden.

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

7

Dies ist die Lösung, die für mich funktioniert ... schrieb sie auch in einer anderen Frage: Wie kann man die Formfarbe dynamisch ändern?

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

3

Für mich funktioniert nichts, aber wenn ich die Farbtonfarbe einstelle, funktioniert es bei Shape Drawable

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

benötigen Android 5.0 API 21


3

Meine Version der Kotlin- Erweiterungsfunktion basiert auf den obigen Antworten mit 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

Der einfache Weg, die Form mit dem Radius zu füllen, ist:

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

1

Vielleicht bin ich zu spät. Aber wenn Sie Kotlin verwenden. Es gibt so einen Weg

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)

Genießen....


0

Für alle, die C # Xamarin verwenden, ist hier eine Methode, die auf Vikrams Snippet basiert:

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;
    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.