Colors & Typography

Colors and text are the two things a user notices in the first half-second of looking at any screen. Android keeps both out of individual layouts and Java files as much as possible, centralizing them into resources instead — this lesson covers colors.xml, color state lists, custom fonts, and the unit Android uses for text size specifically.

colors.xml: One Palette, Defined Once

RecipeBox's entire palette — its primary green, an accent orange for calls to action, and its text colors — lives in a single file:

<!-- res/values/colors.xml -->
<resources>
    <color name="recipe_green">#2E7D32</color>
    <color name="recipe_orange">#EF6C00</color>
    <color name="recipe_text_primary">#212121</color>
    <color name="recipe_text_secondary">#757575</color>
</resources>

Why Not Just Hardcode the Hex Value?

Writing android:textColor="#2E7D32" directly on every TextView works, right up until RecipeBox's brand color needs to change. As covered in Resources Overview, the entire point of externalizing a value is having one place to update it — with a named color, changing the brand green means editing one line in colors.xml; with hardcoded hex values, it means hunting through every layout file that happens to use that shade, and almost certainly missing one.

Color State Lists: Colors That React to View State

Sometimes a single named color isn't enough — a button's text might need to look different when pressed versus disabled. A color state list, defined in res/color/, handles this by picking a different color per state:

<!-- res/color/button_text_color.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:color="@color/recipe_orange" />
    <item android:state_enabled="false" android:color="@color/recipe_text_secondary" />
    <item android:color="@color/recipe_text_primary" />
</selector>
Explanation: Android evaluates the items top to bottom and uses the first one whose condition matches the view's current state; the final item with no condition acts as the default. Referenced the same way as any color: android:textColor="@color/button_text_color".

Custom Fonts

RecipeBox applies a custom font to recipe titles for a bit of visual personality, either bundled directly as font files under res/font/, or fetched on demand through the Downloadable Fonts feature (which pulls the font from Google's font provider instead of shipping it in the APK). Either way, it's applied the same way — through a style:

<!-- res/values/styles.xml -->
<style name="RecipeTitleText">
    <item name="android:fontFamily">@font/lobster_regular</item>
    <item name="android:textSize">20sp</item>
    <item name="android:textColor">@color/recipe_green</item>
</style>

Any TextView already using style="@style/RecipeTitleText" (introduced in Styles & Themes) picks up the new font automatically — no changes needed at each individual usage site.

Material's Typography Scale, Briefly

Material Design defines a small set of named text styles — display (large, short headlines), headline (screen and section titles), and body (regular paragraph text) — rather than leaving every text size as an arbitrary number. As mentioned in Material Components, these are available as ready-made styles like TextAppearance.Material3.HeadlineSmall, which RecipeBox's recipe-detail title and body text extend rather than defining sizes from scratch.

sp vs. dp: Why Text Size Is Different

Nearly every dimension in Android — margins, padding, icon sizes — is measured in dp (density-independent pixels), which scales consistently with screen density but stays fixed regardless of any user preference. Text size uses a different unit, sp (scale-independent pixels), and the difference matters for accessibility:

UnitScales With DensityRespects User's Font-Size Setting
dpYesNo
spYesYes
Why this matters: A user who increases their system font size for readability expects every app's text to grow accordingly. Sizing a TextView in dp instead of sp silently ignores that accessibility setting — the text stays a fixed size no matter what the user has configured, which is why RecipeBox's RecipeTitleText style above uses 20sp, not 20dp.
Up next: Drawables & Vector covers RecipeBox's icons and image resources in more depth.