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?

3 upvote
  flag
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]( developer.android.com/guide/topics/resources/…) states: COMPILED RESOURCE DATATYPE: Resource pointer to a GradientDrawable. – Luis Quijada

11 Answers 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

up vote 241 down vote accepted

You could modify it simply like this

GradientDrawable bgShape = (GradientDrawable)btn.getBackground();
bgShape.setColor(Color.BLACK);
9 upvote
  flag
What is btn.getBackground? – chobo2
upvote
  flag
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. – Ronnie
1 upvote
  flag
Hmm having a hard time to convert this code to monodroid ShapeDrawable bgShape = (ShapeDrawable) Resources.GetDrawable(Resource.Drawable.test); just crashes – chobo2
13 upvote
  flag
I am getting java.lang.ClassCastException: android.graphics.drawable.GradientDrawable cannot be cast to android.graphics.drawable.ShapeDrawable when trying this suggestion. – prolink007
7 upvote
  flag
why is this accepted ? I'm also having the casting error ... – guiomie
upvote
  flag
getting cast exception – Singh Arjun
2 upvote
  flag
Does not work. You will get a cast error. Needs a fix or another answer accepted – ndgreen
4 upvote
  flag
This works just fine. The previous comments are outdates since the answer got edited! – W3hri
1 upvote
  flag
Works great for me as well. – Ruben2112
2 upvote
  flag
shoul use GradientDrawable bgShape = (GradientDrawable)btn.getBackground().getCurrent(); – naveed148
2 upvote
  flag
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
upvote
  flag
Also getting a casting error – Mark O'Sullivan
upvote
  flag
Works for me after several trial and error before finding this answer! Thank you! – codemax

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

So i modified it like this:

((GradientDrawable)someView.getBackground()).setColor(someColor);
1 upvote
  flag
thanks working great :) – Fajar Khan
    LayerDrawable bgDrawable = (LayerDrawable) button.getBackground();
    final GradientDrawable shape = (GradientDrawable)
            bgDrawable.findDrawableByLayerId(R.id.round_button_shape);
    shape.setColor(Color.BLACK);

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: http://i.stack.imgur.com/hKUR7.png

upvote
  flag
This is the correct answer. Both the upwoted above answers were not worked for me. I am getting exception on both of it. – Sanal Varghese

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)

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

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.

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

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

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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.