138

I have

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
   android:shape="rectangle">
    <solid
       android:color="#FFFF00" />
    <padding android:left="7dp"
        android:top="7dp"
        android:right="7dp"
        android:bottom="7dp" />
</shape>

<TextView
    android:background="@drawable/test"
    android:layout_height="45dp"
    android:layout_width="100dp"
    android:text="Moderate"
/>

So now I want this shape to change colors based on information I get back from a web service call. So it could be maybe yellow or green or red or whatever depending on the color I receive from the web serivce call.

How can I change the color of the shape? Based on this information?

Ron
  • 24,175
  • 8
  • 56
  • 97
chobo2
  • 83,322
  • 195
  • 530
  • 832
  • 3
    As appointed by @Couitchy method `View.getBackground()` returns a `GradientDrawable` and not a `ShapeDrawable` causing the app to crash at runtime, due to invalid cast when trying to get the reference and set the color programmatically. [Android Shape doc]( http://developer.android.com/guide/topics/resources/drawable-resource.html#Shape) states: *COMPILED RESOURCE DATATYPE: Resource pointer to a `GradientDrawable`*. – Luis Quijada Jun 08 '13 at 15:37
  • Possible duplicate of [Set android shape color programmatically](https://stackoverflow.com/questions/17823451/set-android-shape-color-programmatically) – Amin Soheyli Apr 24 '19 at 06:35

14 Answers14

304

You could modify it simply like this

GradientDrawable bgShape = (GradientDrawable)btn.getBackground();
bgShape.setColor(Color.BLACK);
Ron
  • 24,175
  • 8
  • 56
  • 97
  • 9
    What is btn.getBackground? – chobo2 Aug 23 '11 at 17:30
  • btn can be any view for which you set the shape drawable from xml. So you can get the drawable back using getBackground() on that view and change its color. – Ron Aug 23 '11 at 17:45
  • 1
    Hmm having a hard time to convert this code to monodroid ShapeDrawable bgShape = (ShapeDrawable) Resources.GetDrawable(Resource.Drawable.test); just crashes – chobo2 Aug 23 '11 at 21:52
  • 16
    I am getting `java.lang.ClassCastException: android.graphics.drawable.GradientDrawable cannot be cast to android.graphics.drawable.ShapeDrawable` when trying this suggestion. – prolink007 Aug 15 '13 at 18:37
  • getting cast exception – Singh Arjun Apr 29 '14 at 12:06
  • 2
    Does not work. You will get a cast error. Needs a fix or another answer accepted – ndgreen Jun 30 '14 at 17:32
  • 7
    This works just fine. The previous comments are outdates since the answer got edited! – W3hri Jul 06 '15 at 13:05
  • 4
    shoul use GradientDrawable bgShape = (GradientDrawable)btn.getBackground().getCurrent(); – naveed148 Sep 09 '16 at 10:52
  • 2
    Works fine but take care that it will change the shape color so next time you use it, it will have the latest color you set. So you need to set the color every time you use this shape drawable. – Beshoy Fayez Nov 04 '16 at 19:37
  • It works only if your drawable XML has only the shape tag inside otherwise it will have a cast error. – André Luiz Reis Mar 13 '18 at 21:06
  • I got a java.lang.ClassCastException: android.graphics.drawable.StateListDrawable cannot be cast to android.graphics.drawable.GradientDrawable but (GradientDrawable)btn.getBackground().getCurrent(); ended up working – Jerry Sha Jan 27 '19 at 03:05
  • you can try for `GradientDrawable bgShape = (GradientDrawable) bubble_text.getBackground().mutate(); bgShape.setColor(color); bgShape.setStroke(1, color);` – Sagar May 21 '19 at 11:58
  • How to get that change color drawable shape as a Drawable? – Abhi S Apr 19 '22 at 09:55
61

For me, it crashed because getBackground returned a GradientDrawable instead of a ShapeDrawable.

So i modified it like this:

((GradientDrawable)someView.getBackground()).setColor(someColor);
SMR
  • 6,628
  • 2
  • 35
  • 56
Couitchy
  • 1,079
  • 10
  • 15
46

This works for me, with an initial xml resource:

example.setBackgroundResource(R.drawable.myshape);
GradientDrawable gd = (GradientDrawable) example.getBackground().getCurrent();
gd.setColor(Color.parseColor("#000000"));
gd.setCornerRadii(new float[]{30, 30, 30, 30, 0, 0, 30, 30});
gd.setStroke(2, Color.parseColor("#00FFFF"), 5, 6);

Result of the above: https://i.stack.imgur.com/hKUR7.png

Manuel V.
  • 463
  • 4
  • 6
11

Maybe someone else need to change color in the XML without create multiple drawables like I needed. Then make a circle drawable without color and then specify backgroundTint for the ImageView.

circle.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
</shape>

And in your layout:

<ImageView
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:background="@drawable/circle"
    android:backgroundTint="@color/red"/>

Edit:

There is a bug regarding this method that prevents it from working on Android Lollipop 5.0 (API level 21). But have been fixed in newer versions.

Community
  • 1
  • 1
nilsi
  • 10,351
  • 10
  • 67
  • 79
11

You can build your own shapes in Java. I did this for an iPhone like Page Controler and paint the shapes in Java:

/**
 * Builds the active and inactive shapes / drawables for the page control
 */
private void makeShapes() {

    activeDrawable = new ShapeDrawable();
    inactiveDrawable = new ShapeDrawable();
    activeDrawable.setBounds(0, 0, (int) mIndicatorSize,
            (int) mIndicatorSize);
    inactiveDrawable.setBounds(0, 0, (int) mIndicatorSize,
            (int) mIndicatorSize);

    int i[] = new int[2];
    i[0] = android.R.attr.textColorSecondary;
    i[1] = android.R.attr.textColorSecondaryInverse;
    TypedArray a = this.getTheme().obtainStyledAttributes(i);

    Shape s1 = new OvalShape();
    s1.resize(mIndicatorSize, mIndicatorSize);
    Shape s2 = new OvalShape();
    s2.resize(mIndicatorSize, mIndicatorSize);

    ((ShapeDrawable) activeDrawable).getPaint().setColor(
            a.getColor(0, Color.DKGRAY));
    ((ShapeDrawable) inactiveDrawable).getPaint().setColor(
            a.getColor(1, Color.LTGRAY));

    ((ShapeDrawable) activeDrawable).setShape(s1);
    ((ShapeDrawable) inactiveDrawable).setShape(s2);
}

hope this helps. Greez Fabian

Fabian
  • 2,693
  • 2
  • 21
  • 33
6
    LayerDrawable bgDrawable = (LayerDrawable) button.getBackground();
    final GradientDrawable shape = (GradientDrawable)
            bgDrawable.findDrawableByLayerId(R.id.round_button_shape);
    shape.setColor(Color.BLACK);
5

circle.xml (drawable)

<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<solid
    android:color="#000"/>

<size
    android:width="10dp"
    android:height="10dp"/>
</shape>

layout

<ImageView
      android:id="@+id/circleColor"
      android:layout_width="15dp"
       android:layout_height="15dp"
      android:textSize="12dp"
       android:layout_gravity="center"
       android:layout_marginLeft="10dp"
      android:background="@drawable/circle"/>

in activity

   circleColor = (ImageView) view.findViewById(R.id.circleColor);
   int color = Color.parseColor("#00FFFF");
   ((GradientDrawable)circleColor.getBackground()).setColor(color);
A. Shukri
  • 115
  • 1
  • 8
2

This solution worked for me using the android sdk v19:

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

If you have an imageView like this:

   <ImageView
    android:id="@+id/color_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginRight="10dp"
    android:src="@drawable/circle_color"/>

which give it a drawable shape as src, you can use this code to change shape's color:

ImageView iv = (ImageView)findViewById(R.id.color_button);
GradientDrawable bgShape = (GradientDrawable)iv.getDrawable();
bgShape.setColor(Color.BLACK);
Hamed Ghadirian
  • 6,159
  • 7
  • 48
  • 67
2

The simplest way to fill the shape with the Radius is:

XML:

<TextView
    android:id="@+id/textView"
    android:background="@drawable/test"
    android:layout_height="45dp"
    android:layout_width="100dp"
    android:text="Moderate"/>

Java:

(textView.getBackground()).setColorFilter(Color.parseColor("#FFDE03"), PorterDuff.Mode.SRC_IN);
SANAT
  • 8,489
  • 55
  • 66
1

My shape xml :

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid  android:color="@android:color/transparent" />
<stroke android:width="0.5dp" android:color="@android:color/holo_green_dark"/>
</shape>

My activity xml :

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="cn.easydone.test.MainActivity">

<android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/AppTheme.AppBarOverlay">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/AppTheme.PopupOverlay" />
    <TextView
        android:id="@+id/test_text"
        android:background="@drawable/bg_stroke_dynamic_color"
        android:padding="20dp"
        android:text="asdasdasdasd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</android.support.design.widget.AppBarLayout>

<android.support.v7.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp"
    android:clipToPadding="false"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />

My activity java :

 TextView testText = (TextView) findViewById(R.id.test_text);
 ((GradientDrawable)testText.getBackground()).setStroke(10,Color.BLACK);

Result picture : result

Abner_Ni
  • 11
  • 1
0

I try Ronnie's answer, and my app crashed. Then I check my drawable xml. It looks like this:

<selector >...</selector>

. I changed it to this:(also changed attributes)

<shape> ... </shape>

It works.

For those who encounter the same problem.

liang
  • 1
  • 2
0

drawable_rectangle.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <solid android:color="@android:color/transparent" />

    <stroke
        android:width="1dp"
        android:color="#9f9f9f" />

    <corners
        android:bottomLeftRadius="5dp"
        android:bottomRightRadius="5dp"
        android:topLeftRadius="5dp"
        android:topRightRadius="5dp" />

</shape>

TextView

<androidx.appcompat.widget.AppCompatTextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/drawable_rectangle"
    android:gravity="center"
    android:padding="10dp"
    android:text="Status"
    android:textColor="@android:color/white"
    android:textSize="20sp" />


public static void changeRectangleColor(View view, int color) {
    ((GradientDrawable) view.getBackground()).setStroke(1, color);
}    

changeRectangleColor(textView, ContextCompat.getColor(context, R.color.colorAccent));
Ketan Ramani
  • 4,874
  • 37
  • 42
0

You can use a binding adapter(Kotlin) to achieve this. Create a binding adapter class named ChangeShapeColor like below

@BindingAdapter("shapeColor")

// Method to load shape and set its color 

fun loadShape(textView: TextView, color: String) {
// first get the drawable that you created for the shape 
val mDrawable = ContextCompat.getDrawable(textView.context, 
R.drawable.language_image_bg)
val  shape =   mDrawable as (GradientDrawable)
// use parse color method to parse #34444 to the int 
shape.setColor(Color.parseColor(color))
 }

Create a drawable shape in res/drawable folder. I have created a circle

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<solid android:color="#anyColorCode"/>

<size
    android:width="@dimen/dp_16"
    android:height="@dimen/dp_16"/>
</shape>

Finally refer it to your view

  <TextView>
   .........
  app:shapeColor="@{modelName.colorString}"
 </Textview>
Rohan Sharma
  • 374
  • 4
  • 11