Android
Shape Color
Programmatically
Android Development
Android UI

Set android shape color programmatically

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Android, a shape background defined in XML is usually a GradientDrawable at runtime. If you want to change its fill color programmatically, the normal pattern is to get the drawable, make sure you are not mutating a shared instance, cast it to GradientDrawable, and call setColor.

Start With a Shape Drawable

A typical XML shape might look like this:

xml
1<!-- res/drawable/rounded_box.xml -->
2<shape xmlns:android="http://schemas.android.com/apk/res/android"
3    android:shape="rectangle">
4    <solid android:color="#DDDDDD" />
5    <corners android:radius="12dp" />
6</shape>

Attach it as a background in layout XML:

xml
1<TextView
2    android:id="@+id/statusView"
3    android:layout_width="wrap_content"
4    android:layout_height="wrap_content"
5    android:background="@drawable/rounded_box"
6    android:text="Status" />

At runtime, that background is typically a GradientDrawable.

Change the Color in Kotlin

Here is the common Kotlin pattern:

kotlin
1import android.graphics.Color
2import android.graphics.drawable.GradientDrawable
3
4val background = statusView.background.mutate() as GradientDrawable
5background.setColor(Color.parseColor("#4CAF50"))

Two parts matter here:

  • 'as GradientDrawable gives access to setColor'
  • 'mutate() prevents changes from affecting other views that use the same drawable resource instance'

Without mutate(), changing one background can unexpectedly recolor other views that share that same XML drawable.

Change the Color in Java

The equivalent Java code looks like this:

java
1import android.graphics.Color;
2import android.graphics.drawable.GradientDrawable;
3
4GradientDrawable background =
5    (GradientDrawable) statusView.getBackground().mutate();
6
7background.setColor(Color.parseColor("#4CAF50"));

This is the same operation, just in Java syntax.

Create the Shape Entirely in Code

If you do not want an XML drawable at all, you can create the shape programmatically:

kotlin
1import android.graphics.Color
2import android.graphics.drawable.GradientDrawable
3
4val drawable = GradientDrawable().apply {
5    shape = GradientDrawable.RECTANGLE
6    cornerRadius = 24f
7    setColor(Color.parseColor("#2196F3"))
8}
9
10statusView.background = drawable

This is useful when the shape itself is dynamic, not just the color.

Use Theme Colors Instead of Hardcoded Values

In real apps, colors often come from resources rather than inline hex strings:

kotlin
1import androidx.core.content.ContextCompat
2
3val color = ContextCompat.getColor(context, R.color.success_green)
4val background = statusView.background.mutate() as GradientDrawable
5background.setColor(color)

That keeps your UI consistent with theming and makes dark mode or design-system updates much easier.

What if the Background Is Not a GradientDrawable

Not every background drawable is a shape XML. It might be:

  • a ColorDrawable
  • a RippleDrawable
  • a StateListDrawable
  • a layered drawable

If the cast fails, inspect the actual drawable type before assuming GradientDrawable.

For example:

kotlin
val drawable = statusView.background
println(drawable::class.java.name)

Sometimes the shape is wrapped inside another drawable, especially when ripple effects or state selectors are involved.

Update Stroke or Corners Too

Once you have a GradientDrawable, you can change more than the fill color:

kotlin
1val background = statusView.background.mutate() as GradientDrawable
2background.setColor(Color.WHITE)
3background.setStroke(4, Color.RED)
4background.cornerRadius = 32f

That makes programmatic shape updates useful for error states, selection highlights, and theme changes.

Common Pitfalls

The biggest pitfall is forgetting mutate(). Drawable resources are often shared, so without mutation you can accidentally recolor other views.

Another common issue is casting blindly to GradientDrawable when the actual runtime drawable is something else, such as a ripple or selector wrapper.

People also often hardcode colors in code when the app already has theme or resource colors defined. That makes long-term UI maintenance harder.

Finally, changing the drawable object does not help if the view later receives a different background from state changes or style updates. Make sure you are modifying the drawable that is actually in use.

Summary

  • Most XML shape backgrounds can be changed at runtime through GradientDrawable.setColor.
  • Call mutate() before editing to avoid affecting shared drawable instances.
  • Use resource or theme colors instead of hardcoded values when possible.
  • Verify the runtime drawable type before casting.
  • Programmatic drawables are a good choice when the shape itself is dynamic.

Course illustration
Course illustration

All Rights Reserved.