Ustaw programowo kolor kształtu Androida

168

Edytuję, aby uprościć pytanie, mając nadzieję, że pomoże to w uzyskaniu dokładnej odpowiedzi.

Powiedz, że mam następujący ovalkształt:

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

Jak programowo ustawić kolor z poziomu klasy aktywności?

Cote Mounyo
źródło
Do czego ustawiasz to rysowanie?
Vikram,
Drawable to ovali jest tłem ImageView.
Cote Mounyo
Jeśli to zadane pytanie jest zbyt trudne, czy istnieje sposób na narysowanie wielu obrazów na płótnie i ustawienie warstwowego produktu końcowego jako tła widoku?
Cote Mounyo
Możesz to osiągnąć, rozszerzając Viewklasę i używając jej jako basewidoku w układzie, który umożliwia nakładanie się widżetów ( RelativeLayout, FrameLayout). W tej rozszerzonej Viewklasie możesz draw multiple images onto a canvas. Ale zanim to zrobisz, spójrz na to -> Link (jeśli jeszcze tego nie zrobiłeś).
Vikram

Odpowiedzi:

266

Uwaga : odpowiedź została zaktualizowana, aby uwzględnić scenariusz, w którym backgroundwystępuje wystąpienie ColorDrawable. Dzięki Tyler Pfaff za wskazanie tego.

To, co można rysować, jest owalem i stanowi tło ImageView

Uzyskać Drawablez imageViewużyciem getBackground():

Drawable background = imageView.getBackground();

Sprawdź przeciwko zwykłym podejrzanym:

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

Wersja kompaktowa:

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

Należy pamiętać, że sprawdzanie wartości null nie jest wymagane.

Jednak powinieneś użyć mutate()na drawables przed ich modyfikacją, jeśli są używane gdzie indziej. (Domyślnie elementy rysunkowe ładowane z XML mają ten sam stan).

Vikram
źródło
3
Dzięki za odpowiedź. (+1). W moim kodzie występują inne błędy, więc trudno go przetestować. Ale nadal może to ustawić solidczęść kształtu. A co z strokeporcją?
Cote Mounyo
1
@TiGer Powinieneś dodać @usernameswój komentarz, aby upewnić się, że powiadomienie zostanie wysłane do użytkownika. Nawiasem mówiąc, będziesz musiał przejść podklasę ShapeDrawable, aby ustawić część obrysu. Więcej informacji tutaj: Link . Spójrz na komentarz, ponieważ wspomina o problemie z zaakceptowaną odpowiedzią.
Vikram
3
android.graphics.drawable.GradientDrawable nie może być rzutowany na android.graphics.drawable.ShapeDrawable Rzutowanie się nie powiedzie
John
3
@John Jeśli Twoje ImageView'stło jest ustawione na a GradientDrawable, getBackground()nie zwróci a ShapeDrawable. Zamiast tego należy użyć GradientDrawable, który jest zwracany: GradientDrawable gradientDrawable = (GradientDrawable)imageView.getBackground();.... gradientDrawable.setColors(new int[] { color1, color2 });.
Vikram
2
Dzięki ... ocalił mój świat.
sid_09
43

Rób jak to:

    ImageView imgIcon = findViewById(R.id.imgIcon);
    GradientDrawable backgroundGradient = (GradientDrawable)imgIcon.getBackground();
    backgroundGradient.setColor(getResources().getColor(R.color.yellow));
Leonly91
źródło
1
@ user3111850 Czy dodałeś android:backgroundswój plik XML, a nawet setBackgroundaktywność, zanim zadzwoniłeś getBackground()? Powinno działać, gdybyś to zrobił.
Lee Yi Hong
41

W dzisiejszych czasach prostszym rozwiązaniem byłoby użycie kształtu jako tła, a następnie programowa zmiana jego koloru poprzez:

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

Aby zapoznać się z dostępnymi opcjami, zobacz PorterDuff.Mode .

AKTUALIZACJA (API 29):

Powyższa metoda jest przestarzała od API 29 i zastąpiona następującą:

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

Aby zapoznać się z dostępnymi opcjami, zobacz BlendMode .

Georgios
źródło
4
Prawidłowy to: view.getBackground().setColorFilter(Color.parseColor("#343434"), PorterDuff.Mode.SRC_ATOP);ponieważ w tle może znajdować się obramowanie lub zaokrąglone pola.
Berkay Turancı,
1
Niezły @ BerkayTurancı mój kształt miał zaokrąglone rogi. Mógłbym pominąć getBackground()połączenie. Mój imageview.src zawierał kształt i użyłem: imageIndicator.setColorFilter(toggleColor, PorterDuff.Mode.SRC_ATOP);gdzie toggleColorjest po prostu int, który poprzednio przechował wynik z getColor ()
Someone Somewhere
1
Posiadanie PorterDuff.Modefor BlendModeColorFilternie kompiluje się tak, jak tego wymaga BlendMode. Więc dla API 29 powinno być view.background.colorFilter = BlendModeColorFilter(Color.parseColor("#343434"), BlendMode.SRC_ATOP).
Onik
Dobry chwyt @Onik. Odpowiednio zaktualizowałem odpowiedź. Dziękuję Ci!
Georgios
14

Spróbuj tego:

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

Więcej szczegółów sprawdź ten link to

mam nadzieję, że pomoże.

androidqq6
źródło
zagłosuj na link. Ale to nie jest odpowiedź na moje pytanie.
Cote Mounyo
13

mam nadzieję, że to pomoże komuś z tym samym problemem

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
źródło
1
Początkowo nie mogłem tego uruchomić, pomyślałem, że twój kolor musi być podany w następujący sposób:gd.setStroke(width_px, Color.parseColor("#FF5722"));
pwnsauce
12

Rozszerzając odpowiedź Vikrama , jeśli kolorujesz dynamiczne widoki, takie jak elementy widoku recyklera, itp. .... Wtedy prawdopodobnie będziesz chciał wywołać mutate () przed ustawieniem koloru. Jeśli tego nie zrobisz, wszystkie widoki, które mają wspólny element do rysowania (tj. Tło), również zostaną zmienione / pokolorowane.

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
źródło
3
potrzeby i dodatkowe sprawdzenie i parametr: if (background instanceof LayerDrawable) { background = ((LayerDrawable) background.mutate()).getDrawable(indexIfLayerDrawable); } if (background instanceof ShapeDrawable)[...]aby poradzić sobie z układami tła, które używają <layer-list ... <item ....
Johny
11

Na to pytanie odpowiedziano jakiś czas temu, ale można je zmodernizować, przepisując jako funkcję rozszerzenia kotlin.

fun Drawable.overrideColor(@ColorInt colorInt: Int) {
    when (this) {
        is GradientDrawable -> setColor(colorInt)
        is ShapeDrawable -> paint.color = colorInt
        is ColorDrawable -> color = colorInt
    }
}
Carlos Paulino
źródło
7

to jest rozwiązanie, które u mnie działa ... napisałam też w innym pytaniu: Jak dynamicznie zmieniać kształt kolorystyczny?

//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)
Społeczność
źródło
4

Nic nie działa dla mnie, ale kiedy ustawię odcień, działa to na Shape Drawable

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

wymaga Android 5.0 API 21

Sumit
źródło
3

Moja wersja funkcji rozszerzenia Kotlin oparta na odpowiedziach powyżej z 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
źródło
1

Prosty sposób wypełnienia kształtu promieniem to:

(view.getBackground()).setColorFilter(Color.parseColor("#FFDE03"), PorterDuff.Mode.SRC_IN);
SANAT
źródło
1

Może jestem za późno, ale jeśli używasz Kotlina. Jest taki sposób

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)

Cieszyć się....

Gorliwy system
źródło
0

Dla każdego, kto używa języka C # Xamarin, oto metoda oparta na fragmencie Vikrama:

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
źródło