Belajar Jetpack Compose - Theming & Material Design
Episode 6 of 23

Belajar Jetpack Compose - Theming & Material Design

Episode ini membangun konsistensi visual lewat MaterialTheme: color scheme, typography, dan shapes, dukungan light dan dark theme, dynamic color di Android 12, serta tokenisasi design system untuk aplikasi berskala.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Pendahuluan

Aplikasi yang rapi tidak lahir dari warna yang dipilih sembarangan. Di balik setiap layar yang enak dilihat ada sistem: kumpulan warna, tipografi, dan bentuk yang konsisten. Di Compose, sistem itu disebut MaterialTheme.

Semua komponen Material 3 yang kalian pakai di episode 4 membaca theme: tombol, teks, dan card otomatis mengambil warna dan bentuk dari theme. Ubah satu token, seluruh aplikasi ikut berubah. Inilah kekuatan theming yang terpusat.

Episode 6 ini meliputi struktur MaterialTheme, dukungan light dan dark, dynamic color, dan design system tokenization.

MaterialTheme: Colors, Typography, dan Shapes

ColorScheme

Setiap aplikasi Compose punya file Theme.kt yang mendefinisikan ColorScheme. Warna tidak disimpan sebagai warna lepas, melainkan sebagai peran: primary, secondary, surface, background, dan seterusnya. Komponen mengambil peran ini, bukan warna langsung.

KotlinColorScheme light
private val LightColors = lightColorScheme(
    primary = Color(0xFF3B5BDB),
    secondary = Color(0xFF5E81AC),
    surface = Color(0xFFFAFAFA),
    onPrimary = Color.White
)

lightColorScheme mengisi peran warna untuk mode terang. Dengan memakai peran, perubahan branding cukup dilakukan di satu tempat — seluruh tombol dan surface ikut menyesuaikan.

Typography dan Shapes

Typography mendefinisikan gaya teks mulai dari displayLarge sampai labelSmall, sedangkan Shapes mengontrol sudut komponen:

KotlinTypography dan Shapes
val AppTypography = Typography(
    headlineMedium = TextStyle(
        fontWeight = FontWeight.Bold,
        fontSize = 28.sp,
        lineHeight = 36.sp
    )
)
 
val AppShapes = Shapes(
    small = RoundedCornerShape(8.dp),
    medium = RoundedCornerShape(12.dp),
    large = RoundedCornerShape(16.dp)
)

Text memakai gaya bawaan seperti headlineMedium lewat MaterialTheme.typography, sehingga hierarki tipografi konsisten di seluruh layar.

Merakit Theme

Semua token diikat dalam satu composable theme:

KotlinMaterialTheme
@Composable
fun BelajarComposeTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colorScheme = if (darkTheme) DarkColors else LightColors
    MaterialTheme(
        colorScheme = colorScheme,
        typography = AppTypography,
        shapes = AppShapes,
        content = content
    )
}

MaterialTheme menyediakan warna, tipografi, dan bentuk ke seluruh subtree. isSystemInDarkTheme() membaca pengaturan sistem — dasar dukungan mode gelap. Untuk melihat hasil theme di perangkat, bangun dan pasang aplikasi dengan ./gradlew :app:installDebug.

Light dan Dark Theme

Dua Set Warna

Mode gelap bukan sekadar warna terbalik. Peran seperti surface dan onSurface perlu diatur ulang agar kontras tetap terjaga di latar gelap. Definisikan DarkColors sebagai pasangan dari LightColors:

KotlinDark color scheme
private val DarkColors = darkColorScheme(
    primary = Color(0xFF8FA8FF),
    secondary = Color(0xFF9BB4E8),
    surface = Color(0xFF121212),
    onPrimary = Color(0xFF1A1A2E)
)

darkColorScheme mengisi peran untuk mode gelap. Dengan pola di atas, aplikasi otomatis berganti theme saat sistem berpindah mode — tanpa logika tambahan di setiap screen.

Menghormati Preferensi Pengguna

Kadang pengguna ingin mengunci theme, misalnya selalu gelap. Simpan preferensi itu di DataStore (episode 11) dan teruskan nilai darkTheme secara eksplisit ke BelajarComposeTheme sebagai parameter.

Dynamic Color dan Material 3

Warna dari Wallpaper

Di Android 12 ke atas, dynamic color mengambil warna dari wallpaper pengguna dan menerapkannya ke aplikasi. dynamicDarkColorScheme dan dynamicLightColorScheme menyediakan skema itu secara otomatis:

KotlinDynamic color
val context = LocalContext.current
val colorScheme = if (dynamicColor && Build.VERSION.SDK_INT >= 31) {
    if (darkTheme) dynamicDarkColorScheme(context)
    else dynamicLightColorScheme(context)
} else {
    if (darkTheme) DarkColors else LightColors
}

dynamicDarkColorScheme(context) menghasilkan skema dari wallpaper. Untuk perangkat di bawah Android 12, kalian jatuh kembali ke skema statis. Fitur ini memberikan rasa personalisasi yang kuat dengan sedikit kode.

Design System Tokenization

Saat tim tumbuh, token harus dibakukan. Kumpulkan semua nilai dalam satu object yang bisa dipakai di mana saja:

KotlinDesign token
object Spacing {
    val xs = 4.dp
    val sm = 8.dp
    val md = 16.dp
    val lg = 24.dp
}
 
object Dimensi {
    val radiusCard = 16.dp
    val tinggiTopBar = 64.dp
}

Token seperti Spacing.md menggantikan angka ajaib di seluruh codebase. Perubahan desain cukup dilakukan di object ini — konsistensi dan kecepatan iterasi naik bersama-sama.

Penutup

Episode 6 membangun sistem visual: MaterialTheme dengan ColorScheme, Typography, dan Shapes, dukungan light dan dark theme lewat isSystemInDarkTheme, dynamic color di Android 12 dengan dynamicLightColorScheme, serta tokenisasi design system untuk aplikasi berskala.

Inti yang harus dibawa pulang:

  • Warna disimpan sebagai peran di ColorScheme, bukan warna lepas.
  • Typography dan Shapes menyatukan hierarki teks dan bentuk komponen.
  • isSystemInDarkTheme menghubungkan theme dengan mode sistem.
  • Dynamic color mengambil warna wallpaper di Android 12 ke atas.
  • Token object menggantikan angka ajaib di seluruh codebase.
  • MaterialTheme menyediakan semua token ke subtree sekaligus.

Di episode 7 selanjutnya kita akan membahas handling input dan events — TextField, Button, Checkbox, dan Switch, deteksi gesture, fokus dan keyboard, validasi input, serta Snackbar, dialog, dan bottom sheet.

Belajar Jetpack Compose - Theming & Material Design | Belajar Jetpack Compose