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?

Cote Mounyo
quelle
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.)

Vikram
quelle
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));
Leonly91
quelle
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 .

Georgios
quelle
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.

androidqq6
quelle
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);
medhdj
quelle
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");
    }

}
Tyler Pfaff
quelle
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
    }
}
Carlos Paulino
quelle
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)
Gemeinschaft
quelle
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

Sumit
quelle
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")
    }
}
Sattar Hummatli
quelle
1

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

(view.getBackground()).setColorFilter(Color.parseColor("#FFDE03"), PorterDuff.Mode.SRC_IN);
SANAT
quelle
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....

Eifriges System
quelle
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;
    }
}
Ryan
quelle