Phase 1 · Getting Started with ComposeModule 7~26 min read

Images, Icons & Resources

Show images and Material icons, and use Android's resource system for strings, colors, and drawables.

What you'll learn

Apps aren't just text. This module covers showing images and icons, and Android's resources system — the proper home for your images, strings, and colours. You'll also learn the accessibility habit every image needs.

By the end you'll be able to:

  • Use the resources folder and the R class
  • Display images with Image and painterResource
  • Add Material Icons
  • Write good contentDescriptions for accessibility

The resources system

Android keeps non-code assets in the res/ folder, and generates an R class so you can reference them safely in Kotlin. Instead of hard-coding a photo path or a piece of text, you point at a resource — which makes translation, theming, and different screen densities possible:

ResourceLives inReferenced as
Images / drawablesres/drawable/R.drawable.profile
Stringsres/values/strings.xmlR.string.app_name
Colorsres/values/colors.xmlR.color.brand
Launcher iconres/mipmap/the app icon

Tip

Always put user-facing text in strings.xml and read it with stringResource(R.string.x), rather than hard-coding it in your composables. It's the difference between an app you can translate into other languages later and one you can't.

Images

The Image composable shows a picture; painterResource loads one from your drawables. Two touches make images look right: contentScale decides how the image fills its box (Crop fills and crops, Fit shows it whole), and Modifier.clip(CircleShape) makes the classic round avatar:

Avatar.kt
Image(
    painter = painterResource(R.drawable.profile),
    contentDescription = "Ada's profile photo",
    contentScale = ContentScale.Crop,   // fill the box, cropping overflow
    modifier = Modifier
        .size(96.dp)
        .clip(CircleShape),              // round avatar
)
9:41
A
♥Like
Image + Icon — how this renders on a device

Note

To load an image from the internet (a URL), the standard tool is the Coillibrary's AsyncImage — you'll meet it once you start networking in Phase 4. For now, painterResource covers images bundled in your app.

Icons

Material Design ships a large set of icons available as Icons.Default.* (and other styles). The Icon composable draws them and a tint colours them. Icons are vectors, so they stay crisp at any size:

Icons.kt
Icon(
    imageVector = Icons.Default.Favorite,
    contentDescription = "Like",
    tint = Color.Red,
)

// Pull user-facing text from resources, not hard-coded strings:
Text(text = stringResource(R.string.app_name))

contentDescription

Both Image and Icon require a contentDescription — a text description read aloud by TalkBack, Android's screen reader. Describe the image's meaning ("Ada's profile photo"), not the word "image." If a graphic is purely decorative and adds no information, pass null so the screen reader skips it.

Key idea

Accessibility isn't optional. A meaningful contentDescription is the difference between an app a blind user can navigate and one they can't — and Compose makes you supply it, so take the moment to write a good one (or null when it's truly decorative).

Recap & quick check

Key takeaways

  • Non-code assets live in res/; the generated R class references them (R.drawable.x, R.string.x).
  • Put user-facing text in strings.xml and read it with stringResource — it enables translation.
  • Image + painterResource shows a bundled picture; contentScale and clip control fit and shape.
  • Material Icons are available as Icons.Default.*; Icon draws them and tint colours them.
  • Image/Icon require a contentDescription for screen readers — describe meaning, or null if decorative.

Quick check

1. How do you reference a bundled image named profile.png in code?

2. Why put text in strings.xml instead of hard-coding it?

3. Which contentScale fills the box and crops the overflow?

4. What is contentDescription for?

5. How do you make a square image into a round avatar?

Your UIs can look rich now — but they're still static. In the final module of Phase 1 we make them interactive with state.