Android
Material Design
AppCompat
Button Styling
UI Design

Coloring Buttons in Android with Material Design and AppCompat

Master System Design with Codemia

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

Introduction

Coloring Android buttons is easiest when you work with the theme and tint system rather than replacing the background drawable manually. Material Design components already know how to handle shape, elevation, ripple, disabled state, and text contrast, so the goal is usually to tint correctly without throwing those behaviors away.

The exact approach depends on whether you are using MaterialButton or an older AppCompatButton. In modern apps, MaterialButton plus theme colors is usually the cleanest answer.

Prefer Theme Colors Over Hardcoded Backgrounds

If the app uses a Material Components theme, many button colors can come from theme attributes such as colorPrimary and colorOnPrimary.

xml
<!-- res/values/colors.xml -->
<color name="brand_primary">#00695C</color>
<color name="brand_on_primary">#FFFFFF</color>
xml
1<!-- res/values/themes.xml -->
2<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight.NoActionBar">
3    <item name="colorPrimary">@color/brand_primary</item>
4    <item name="colorOnPrimary">@color/brand_on_primary</item>
5</style>

Once that is in place, a plain MaterialButton already looks consistent with the app's design system:

xml
1<com.google.android.material.button.MaterialButton
2    android:layout_width="wrap_content"
3    android:layout_height="wrap_content"
4    android:text="Save" />

This approach scales well because the button color is defined once and reused across the app.

Tint A Specific Button Instead Of Replacing Its Background

If one button needs a special color, use backgroundTint or the equivalent Material attribute. That preserves the component's built-in behavior.

xml
1<com.google.android.material.button.MaterialButton
2    android:layout_width="wrap_content"
3    android:layout_height="wrap_content"
4    android:text="Delete"
5    android:textColor="@android:color/white"
6    app:backgroundTint="@color/red_700" />

This is better than setting a fully custom background drawable in many cases because ripple and shape behavior remain intact.

Use ColorStateList For Real UI States

A single flat color is rarely enough. Buttons should usually look different when disabled, pressed, or checked. A ColorStateList handles that cleanly:

xml
1<!-- res/color/button_tint.xml -->
2<selector xmlns:android="http://schemas.android.com/apk/res/android">
3    <item android:state_enabled="false" android:color="#BDBDBD" />
4    <item android:color="#00695C" />
5</selector>

Apply it like this:

xml
1<com.google.android.material.button.MaterialButton
2    android:layout_width="wrap_content"
3    android:layout_height="wrap_content"
4    android:text="Submit"
5    android:textColor="@android:color/white"
6    app:backgroundTint="@color/button_tint" />

That gives you better behavior than manually swapping colors in code whenever the enabled state changes.

AppCompat Still Works, But Material Is Better

If the screen still uses AppCompatButton, you can tint it as well:

xml
1<androidx.appcompat.widget.AppCompatButton
2    android:layout_width="wrap_content"
3    android:layout_height="wrap_content"
4    android:text="Legacy"
5    android:backgroundTint="@color/button_tint"
6    android:textColor="@android:color/white" />

This works for simpler screens, but MaterialButton gives you more predictable Material styling, especially for outlined buttons, shapes, icons, and ripple behavior.

For an outlined Material button, stroke color matters more than fill:

xml
1<com.google.android.material.button.MaterialButton
2    style="@style/Widget.MaterialComponents.Button.OutlinedButton"
3    android:layout_width="wrap_content"
4    android:layout_height="wrap_content"
5    android:text="More Info"
6    android:textColor="@color/brand_primary"
7    app:strokeColor="@color/button_tint" />

Different button styles communicate different emphasis, so they should not all be colored the same way.

Programmatic Tinting

You can also update tint in code when the screen state changes dynamically:

kotlin
val button = findViewById<com.google.android.material.button.MaterialButton>(R.id.confirmButton)
button.backgroundTintList = getColorStateList(R.color.button_tint)
button.setTextColor(getColor(android.R.color.white))

Use code-based coloring when the state is dynamic. For static brand styling, XML is usually easier to maintain.

It also keeps the design system reviewable in one place instead of hiding color decisions across multiple activities and fragments.

Common Pitfalls

One common mistake is replacing the background drawable entirely and then wondering why the ripple or shape no longer behaves like a Material button. Another is hardcoding a single color without accounting for disabled state. Developers also often forget contrast, which leads to text that technically compiles but is hard to read. Finally, mixing AppCompatButton and MaterialButton without understanding their different styling expectations often produces inconsistent screens.

Summary

  • Prefer MaterialButton and theme-driven colors for Material Design apps.
  • Use backgroundTint and ColorStateList rather than replacing the background blindly.
  • Theme attributes scale better than scattered hardcoded colors.
  • 'AppCompatButton can be tinted, but MaterialButton usually gives better Material behavior.'
  • Always check text contrast and disabled-state appearance, not just the default enabled color.

Course illustration
Course illustration

All Rights Reserved.