Penerapan Tema Material dengan Jetpack Compose

1. Sebelum memulai

Desain Material adalah sistem desain yang dibuat dan didukung oleh desainer dan developer Google guna menciptakan pengalaman digital berkualitas tinggi untuk Android, serta platform seluler dan web lainnya. Panduan ini berisi langkah-langkah cara membangun UI aplikasi Anda dengan cara yang mudah dibaca, menarik, dan konsisten.

Dalam codelab ini, Anda akan mempelajari Penerapan Tema Material yang memungkinkan Anda menggunakan Desain Material di aplikasi Anda, dengan panduan tentang penyesuaian warna, tipografi, dan bentuk. Anda dapat menyesuaikan sesedikit atau sebanyak yang Anda inginkan untuk aplikasi Anda. Anda juga akan mempelajari cara menambahkan panel aplikasi atas untuk menampilkan nama dan ikon aplikasi.

Prasyarat

  • Pemahaman tentang bahasa Kotlin, termasuk sintaksis, fungsi, dan variabel.
  • Mampu membangun tata letak di Compose, termasuk baris dan kolom dengan padding.
  • Dapat membuat daftar sederhana di Compose.

Yang akan Anda pelajari

  • Cara menerapkan Tema Material ke aplikasi Compose.
  • Cara menambahkan palet warna kustom ke aplikasi Anda.
  • Cara menambahkan font kustom ke aplikasi Anda.
  • Cara menambahkan bentuk kustom ke elemen di aplikasi Anda.
  • Cara menambahkan panel aplikasi atas ke aplikasi Anda.

Yang akan Anda bangun

  • Anda akan membuat aplikasi menarik yang menggabungkan praktik terbaik Desain Material.

Yang Anda butuhkan

  • Versi terbaru Android Studio.
  • Koneksi internet untuk mendownload kode awal dan font.

2. Ringkasan aplikasi

Dalam codelab ini, Anda akan membuat Woof, yaitu aplikasi yang menampilkan daftar anjing dan menggunakan Desain Material untuk membuat pengalaman aplikasi yang menarik.

92eca92f64b029cf.png

Melalui codelab ini, kami akan menunjukkan beberapa hal yang mungkin dilakukan menggunakan Penerapan Tema Material. Gunakan codelab ini untuk menemukan ide tentang cara menggunakan Tema Material untuk meningkatkan tampilan dan nuansa aplikasi yang Anda buat di masa mendatang.

Palet warna

Berikut adalah palet warna untuk tema terang dan gelap yang akan kita buat.

Gambar ini memiliki skema warna terang untuk aplikasi Woof.

Gambar ini memiliki skema warna gelap untuk aplikasi Woof.

Berikut adalah aplikasi final dalam tema terang dan tema gelap.

Tema terang

Tema gelap

Tipografi

Berikut adalah gaya jenis yang akan Anda gunakan di aplikasi.

8ea685b3871d5ffc.png

File tema

File Theme.kt adalah file yang menyimpan semua informasi tentang tema aplikasi, yang ditentukan melalui warna, tipografi, dan bentuk. File ini penting untuk Anda ketahui. Di dalam file terdapat WoofTheme() composable, yang menetapkan warna, tipografi, dan bentuk aplikasi.

@Composable
fun WoofTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    // Dynamic color is available on Android 12+
    dynamicColor: Boolean = false,
    content: @Composable () -> Unit
) {
    val colorScheme = when {
        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            val context = LocalContext.current
            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
        }

        darkTheme -> DarkColors
        else -> LightColors
    }
    val view = LocalView.current
    if (!view.isInEditMode) {
        SideEffect {
            setUpEdgeToEdge(view, darkTheme)
        }
    }

    MaterialTheme(
        colorScheme = colorScheme,
        shapes = Shapes,
        typography = Typography,
        content = content
    )
}

/**
 * Sets up edge-to-edge for the window of this [view]. The system icon colors are set to either
 * light or dark depending on whether the [darkTheme] is enabled or not.
 */
private fun setUpEdgeToEdge(view: View, darkTheme: Boolean) {
    val window = (view.context as Activity).window
    WindowCompat.setDecorFitsSystemWindows(window, false)
    window.statusBarColor = Color.Transparent.toArgb()
    val navigationBarColor = when {
        Build.VERSION.SDK_INT >= 29 -> Color.Transparent.toArgb()
        Build.VERSION.SDK_INT >= 26 -> Color(0xFF, 0xFF, 0xFF, 0x63).toArgb()
        // Min sdk version for this app is 24, this block is for SDK versions 24 and 25
        else -> Color(0x00, 0x00, 0x00, 0x50).toArgb()
    }
    window.navigationBarColor = navigationBarColor
    val controller = WindowCompat.getInsetsController(window, view)
    controller.isAppearanceLightStatusBars = !darkTheme
    controller.isAppearanceLightNavigationBars = !darkTheme
}

Di MainActivity.kt, WoofTheme() ditambahkan untuk menyediakan Penerapan Tema Material untuk seluruh aplikasi.

class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           WoofTheme {
               Surface(
                   modifier = Modifier.fillMaxSize()
               ) {
                   WoofApp()
               }
           }
       }
   }
}

Lihat WoofPreview(). WoofTheme() ditambahkan untuk menyediakan Penerapan Tema Material yang Anda lihat di WoofPreview().

@Preview
@Composable
fun WoofPreview() {
    WoofTheme(darkTheme = false) {
        WoofApp()
    }
}

3. Mendapatkan kode awal

Untuk memulai, download kode awal:

Atau, Anda dapat membuat clone repositori GitHub untuk kode tersebut:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-woof.git
$ cd basic-android-kotlin-compose-training-woof
$ git checkout starter

Anda dapat menjelajahi kode di repositori GitHub Woof app.

Mempelajari kode awal

  1. Buka kode awal di Android Studio.
  2. Buka com.example.woof > data > Dog.kt. File ini berisi Dog data class yang akan digunakan untuk mewakili foto, nama, usia, dan hobi anjing. File ini juga berisi daftar anjing dan informasi yang akan Anda gunakan sebagai data di aplikasi Anda.
  3. Buka res > drawable. File ini berisi semua aset gambar yang Anda butuhkan untuk project ini, termasuk ikon aplikasi, gambar anjing, dan ikon.
  4. Buka res > values > strings.xml. File ini berisi string yang Anda gunakan dalam aplikasi ini, termasuk nama aplikasi, nama anjing, deskripsinya, dan lainnya.
  5. Buka MainActivity.kt. File ini berisi kode untuk membuat daftar sederhana yang menampilkan foto anjing, nama anjing, dan usia anjing tersebut.
  6. WoofApp() berisi LazyColumn yang menampilkan DogItem.
  7. DogItem() berisi Row yang menampilkan foto anjing dan informasi tentangnya.
  8. DogIcon() menampilkan foto anjing.
  9. DogInformation() menampilkan nama dan usia anjing.
  10. WoofPreview() memungkinkan Anda melihat pratinjau aplikasi di panel Design.

Memastikan emulator/perangkat Anda bertema terang

Dalam codelab ini, Anda akan menggunakan tema terang dan gelap, tetapi sebagian besar codelab ini menggunakan tema terang. Sebelum memulai, pastikan perangkat/emulator Anda memiliki tema terang.

Untuk melihat aplikasi Anda dalam tema terang, di emulator atau perangkat fisik Anda:

  1. Buka aplikasi Setelan di perangkat.
  2. Telusuri Tema gelap dan klik di dalamnya.
  3. Jika Tema gelap aktif, nonaktifkan.

Jalankan kode awal untuk melihat titik awal Anda, yaitu daftar yang menampilkan anjing beserta foto, nama, dan usianya. Meskipun sudah berfungsi, tampaknya tidak bagus, jadi kita akan memperbaikinya.

6d253ae50c63014d.png

4. Menambahkan warna

Hal pertama yang akan Anda ubah di aplikasi Woof adalah skema warna.

Skema warna adalah kombinasi warna yang digunakan aplikasi Anda. Kombinasi warna yang berbeda membangkitkan suasana hati yang berbeda, yang memengaruhi perasaan orang saat menggunakan aplikasi Anda.

Warna, dalam sistem Android, diwakili oleh nilai warna heksadesimal (hex). Kode warna heksadesimal dimulai dengan tanda pagar (#), dan diikuti dengan enam huruf dan/atau angka yang mewakili komponen merah, hijau, dan biru (RGB) dari warna tersebut. Dua huruf/angka pertama merujuk ke warna merah, dua huruf berikutnya berwarna hijau, dan dua huruf terakhir mengacu pada warna biru.

Ini menunjukkan angka heksadesimal yang digunakan untuk membuat warna.

Warna juga dapat menyertakan nilai alfa—huruf dan/atau angka—yang mewakili transparansi warna (#00 adalah opasitas 0% (transparan sepenuhnya), #FF adalah opasitas 100% (solid sepenuhnya). Jika disertakan, nilai alfa adalah dua karakter pertama dari kode warna heksadesimal setelah tanda pagar (#). Jika nilai alfa tidak disertakan, nilai tersebut diasumsikan sebagai #FF, yaitu opasitas 100% (solid sepenuhnya).

Berikut adalah beberapa contoh warna dan nilai heksadesimalnya.

2753d8cdd396c449.png

Menggunakan Material Theme Builder untuk membuat skema warna

Untuk membuat skema warna kustom bagi aplikasi, kita akan menggunakan Material Theme Builder.

  1. Klik link ini untuk membuka Material Theme Builder.
  2. Di panel kiri, Anda akan melihat Core Colors, klik Primary:

Panel ini menunjukkan empat warna inti di Material Theme Builder

  1. Pemilih warna HCT akan terbuka.

Ini adalah Pemilih Warna HCT untuk memilih warna kustom di Material Theme Builder.

  1. Untuk membuat skema warna yang ditampilkan di screenshot aplikasi, Anda akan mengubah warna primer di pemilih warna ini. Di kotak teks, ganti teks saat ini dengan #006C4C. Tindakan ini akan membuat warna primer aplikasi menjadi hijau.

Gambar ini menunjukkan pemilih Warna HCT disetel ke hijau

Perhatikan cara ini memperbarui aplikasi di layar untuk mengadopsi skema warna hijau.

Gambar ini menunjukkan aplikasi Material Theme Builder yang bereaksi terhadap perubahan warna dari pemilih warna HCT.

  1. Scroll halaman ke bawah dan Anda akan melihat skema warna penuh untuk tema terang dan gelap yang dihasilkan dari warna yang Anda masukkan.

Skema Terang Material Theme Builder

Skema Gelap yang dibuat dengan Material Theme Builder

Anda mungkin bertanya-tanya apa saja peran ini dan bagaimana peran tersebut digunakan. Berikut ini beberapa peran utamanya:

  • Warna primer digunakan untuk komponen utama di seluruh UI.
  • Warna sekunder digunakan untuk komponen yang bukan utama di UI.
  • Warna tersier digunakan untuk aksen kontras yang dapat digunakan untuk menyeimbangkan warna primer dan sekunder atau membawa perhatian tinggi pada elemen, seperti kolom input.
  • Elemen warna on muncul di atas warna lain pada palet, dan terutama diterapkan pada teks, ikonografi, dan goresan. Pada palet warna, kita memiliki warna onSurface, yang muncul di atas warna platform, dan warna onPrimary, yang muncul di atas warna primer.

Slot ini akan menghasilkan sistem desain yang kohesif, dengan komponen terkait yang diberi warna serupa.

Cukup teori tentang warna—saatnya untuk menambahkan palet warna yang indah ini ke aplikasi!

Menambahkan palet warna ke tema

Di halaman Material Theme Builder, ada opsi untuk mengklik tombol Export guna mendownload file Color.kt dan file Theme.kt dengan tema kustom yang Anda buat di Theme Builder.

Tombol ini akan bekerja untuk menambahkan tema kustom yang telah kita buat ke aplikasi. Namun, karena file Theme.kt yang dihasilkan tidak menyertakan kode untuk warna dinamis yang akan kita bahas nanti di codelab, salin file tersebut.

  1. Buka file Color.kt dan ganti konten dengan kode di bawah ini untuk menyalin dalam skema warna baru.
package com.example.woof.ui.theme

import androidx.compose.ui.graphics.Color

val md_theme_light_primary = Color(0xFF006C4C)
val md_theme_light_onPrimary = Color(0xFFFFFFFF)
val md_theme_light_primaryContainer = Color(0xFF89F8C7)
val md_theme_light_onPrimaryContainer = Color(0xFF002114)
val md_theme_light_secondary = Color(0xFF4D6357)
val md_theme_light_onSecondary = Color(0xFFFFFFFF)
val md_theme_light_secondaryContainer = Color(0xFFCFE9D9)
val md_theme_light_onSecondaryContainer = Color(0xFF092016)
val md_theme_light_tertiary = Color(0xFF3D6373)
val md_theme_light_onTertiary = Color(0xFFFFFFFF)
val md_theme_light_tertiaryContainer = Color(0xFFC1E8FB)
val md_theme_light_onTertiaryContainer = Color(0xFF001F29)
val md_theme_light_error = Color(0xFFBA1A1A)
val md_theme_light_errorContainer = Color(0xFFFFDAD6)
val md_theme_light_onError = Color(0xFFFFFFFF)
val md_theme_light_onErrorContainer = Color(0xFF410002)
val md_theme_light_background = Color(0xFFFBFDF9)
val md_theme_light_onBackground = Color(0xFF191C1A)
val md_theme_light_surface = Color(0xFFFBFDF9)
val md_theme_light_onSurface = Color(0xFF191C1A)
val md_theme_light_surfaceVariant = Color(0xFFDBE5DD)
val md_theme_light_onSurfaceVariant = Color(0xFF404943)
val md_theme_light_outline = Color(0xFF707973)
val md_theme_light_inverseOnSurface = Color(0xFFEFF1ED)
val md_theme_light_inverseSurface = Color(0xFF2E312F)
val md_theme_light_inversePrimary = Color(0xFF6CDBAC)
val md_theme_light_shadow = Color(0xFF000000)
val md_theme_light_surfaceTint = Color(0xFF006C4C)
val md_theme_light_outlineVariant = Color(0xFFBFC9C2)
val md_theme_light_scrim = Color(0xFF000000)

val md_theme_dark_primary = Color(0xFF6CDBAC)
val md_theme_dark_onPrimary = Color(0xFF003826)
val md_theme_dark_primaryContainer = Color(0xFF005138)
val md_theme_dark_onPrimaryContainer = Color(0xFF89F8C7)
val md_theme_dark_secondary = Color(0xFFB3CCBE)
val md_theme_dark_onSecondary = Color(0xFF1F352A)
val md_theme_dark_secondaryContainer = Color(0xFF354B40)
val md_theme_dark_onSecondaryContainer = Color(0xFFCFE9D9)
val md_theme_dark_tertiary = Color(0xFFA5CCDF)
val md_theme_dark_onTertiary = Color(0xFF073543)
val md_theme_dark_tertiaryContainer = Color(0xFF244C5B)
val md_theme_dark_onTertiaryContainer = Color(0xFFC1E8FB)
val md_theme_dark_error = Color(0xFFFFB4AB)
val md_theme_dark_errorContainer = Color(0xFF93000A)
val md_theme_dark_onError = Color(0xFF690005)
val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
val md_theme_dark_background = Color(0xFF191C1A)
val md_theme_dark_onBackground = Color(0xFFE1E3DF)
val md_theme_dark_surface = Color(0xFF191C1A)
val md_theme_dark_onSurface = Color(0xFFE1E3DF)
val md_theme_dark_surfaceVariant = Color(0xFF404943)
val md_theme_dark_onSurfaceVariant = Color(0xFFBFC9C2)
val md_theme_dark_outline = Color(0xFF8A938C)
val md_theme_dark_inverseOnSurface = Color(0xFF191C1A)
val md_theme_dark_inverseSurface = Color(0xFFE1E3DF)
val md_theme_dark_inversePrimary = Color(0xFF006C4C)
val md_theme_dark_shadow = Color(0xFF000000)
val md_theme_dark_surfaceTint = Color(0xFF6CDBAC)
val md_theme_dark_outlineVariant = Color(0xFF404943)
val md_theme_dark_scrim = Color(0xFF000000)
  1. Buka file Theme.kt dan ganti konten dengan kode di bawah ini untuk menambahkan warna baru ke tema.
package com.example.woof.ui.theme

import android.app.Activity
import android.os.Build
import android.view.View
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat

private val LightColors = lightColorScheme(
    primary = md_theme_light_primary,
    onPrimary = md_theme_light_onPrimary,
    primaryContainer = md_theme_light_primaryContainer,
    onPrimaryContainer = md_theme_light_onPrimaryContainer,
    secondary = md_theme_light_secondary,
    onSecondary = md_theme_light_onSecondary,
    secondaryContainer = md_theme_light_secondaryContainer,
    onSecondaryContainer = md_theme_light_onSecondaryContainer,
    tertiary = md_theme_light_tertiary,
    onTertiary = md_theme_light_onTertiary,
    tertiaryContainer = md_theme_light_tertiaryContainer,
    onTertiaryContainer = md_theme_light_onTertiaryContainer,
    error = md_theme_light_error,
    errorContainer = md_theme_light_errorContainer,
    onError = md_theme_light_onError,
    onErrorContainer = md_theme_light_onErrorContainer,
    background = md_theme_light_background,
    onBackground = md_theme_light_onBackground,
    surface = md_theme_light_surface,
    onSurface = md_theme_light_onSurface,
    surfaceVariant = md_theme_light_surfaceVariant,
    onSurfaceVariant = md_theme_light_onSurfaceVariant,
    outline = md_theme_light_outline,
    inverseOnSurface = md_theme_light_inverseOnSurface,
    inverseSurface = md_theme_light_inverseSurface,
    inversePrimary = md_theme_light_inversePrimary,
    surfaceTint = md_theme_light_surfaceTint,
    outlineVariant = md_theme_light_outlineVariant,
    scrim = md_theme_light_scrim,
)

private val DarkColors = darkColorScheme(
    primary = md_theme_dark_primary,
    onPrimary = md_theme_dark_onPrimary,
    primaryContainer = md_theme_dark_primaryContainer,
    onPrimaryContainer = md_theme_dark_onPrimaryContainer,
    secondary = md_theme_dark_secondary,
    onSecondary = md_theme_dark_onSecondary,
    secondaryContainer = md_theme_dark_secondaryContainer,
    onSecondaryContainer = md_theme_dark_onSecondaryContainer,
    tertiary = md_theme_dark_tertiary,
    onTertiary = md_theme_dark_onTertiary,
    tertiaryContainer = md_theme_dark_tertiaryContainer,
    onTertiaryContainer = md_theme_dark_onTertiaryContainer,
    error = md_theme_dark_error,
    errorContainer = md_theme_dark_errorContainer,
    onError = md_theme_dark_onError,
    onErrorContainer = md_theme_dark_onErrorContainer,
    background = md_theme_dark_background,
    onBackground = md_theme_dark_onBackground,
    surface = md_theme_dark_surface,
    onSurface = md_theme_dark_onSurface,
    surfaceVariant = md_theme_dark_surfaceVariant,
    onSurfaceVariant = md_theme_dark_onSurfaceVariant,
    outline = md_theme_dark_outline,
    inverseOnSurface = md_theme_dark_inverseOnSurface,
    inverseSurface = md_theme_dark_inverseSurface,
    inversePrimary = md_theme_dark_inversePrimary,
    surfaceTint = md_theme_dark_surfaceTint,
    outlineVariant = md_theme_dark_outlineVariant,
    scrim = md_theme_dark_scrim,
)

@Composable
fun WoofTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    // Dynamic color is available on Android 12+
    dynamicColor: Boolean = false,
    content: @Composable () -> Unit
) {
    val colorScheme = when {
        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            val context = LocalContext.current
            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
        }

        darkTheme -> DarkColors
        else -> LightColors
    }
    val view = LocalView.current
    if (!view.isInEditMode) {
        SideEffect {
            setUpEdgeToEdge(view, darkTheme)
        }
    }

    MaterialTheme(
        colorScheme = colorScheme,
        shapes = Shapes,
        typography = Typography,
        content = content
    )
}

/**
 * Sets up edge-to-edge for the window of this [view]. The system icon colors are set to either
 * light or dark depending on whether the [darkTheme] is enabled or not.
 */
private fun setUpEdgeToEdge(view: View, darkTheme: Boolean) {
    val window = (view.context as Activity).window
    WindowCompat.setDecorFitsSystemWindows(window, false)
    window.statusBarColor = Color.Transparent.toArgb()
    val navigationBarColor = when {
        Build.VERSION.SDK_INT >= 29 -> Color.Transparent.toArgb()
        Build.VERSION.SDK_INT >= 26 -> Color(0xFF, 0xFF, 0xFF, 0x63).toArgb()
        // Min sdk version for this app is 24, this block is for SDK versions 24 and 25
        else -> Color(0x00, 0x00, 0x00, 0x50).toArgb()
    }
    window.navigationBarColor = navigationBarColor
    val controller = WindowCompat.getInsetsController(window, view)
    controller.isAppearanceLightStatusBars = !darkTheme
    controller.isAppearanceLightNavigationBars = !darkTheme
}

Di WoofTheme(), colorScheme val menggunakan pernyataan when

  • Jika dynamicColor bernilai benar dan versi build adalah S atau yang lebih tinggi, perangkat akan diperiksa apakah menggunakan darkTheme atau tidak.
  • Jika temanya gelap, colorScheme akan disetel ke dynamicDarkColorScheme.
  • Jika tidak dalam tema gelap, warna akan disetel ke dynamicLightColorScheme.
  • Jika aplikasi tidak menggunakan dynamicColorScheme, aplikasi akan diperiksa apakah menggunakan darkTheme. Jika demikian, colorScheme akan ditetapkan ke DarkColors.
  • Jika tidak ada yang benar, colorScheme akan ditetapkan ke LightColors.

File yang disalin di Theme.kt memiliki dynamicColor yang disetel ke salah dan perangkat yang kita gunakan dalam mode terang sehingga colorScheme akan disetel ke LightColors.

val colorScheme = when {
       dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
           val context = LocalContext.current
           if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
       }

       darkTheme -> DarkColors
       else -> LightColors
   }
  1. Jalankan kembali aplikasi Anda, perhatikan bahwa panel aplikasi telah otomatis berubah warna.

b48b3fa2ecec9b86.png

Pemetaan warna

Komponen material dipetakan ke slot warna secara otomatis. Komponen utama lainnya di seluruh UI, seperti Tombol Tindakan Mengambang (FAB), juga disetel ke warna Primer sebagai default. Ini berarti Anda tidak perlu menetapkan warna secara eksplisit ke komponen karena akan otomatis dipetakan ke slot warna saat Anda menetapkan tema warna di aplikasi. Anda dapat menggantinya dengan menetapkan warna secara eksplisit dalam kode. Baca selengkapnya tentang peran warna di sini.

Di bagian ini, kita akan menggabungkan Row yang berisi DogIcon() dan DogInformation() dengan Card untuk membedakan warna item daftar dengan latar belakang.

  1. Dalam fungsi composable DogItem(), gabungkan Row() dengan Card().
Card() {
   Row(
       modifier = modifier
           .fillMaxWidth()
           .padding(dimensionResource(id = R.dimen.padding_small))
   ) {
       DogIcon(dog.imageResourceId)
       DogInformation(dog.name, dog.age)
   }
}
  1. Karena Card kini merupakan composable turunan pertama di DogItem(), teruskan pengubah dari DogItem() ke Card, dan update pengubah Row ke instance baru Modifier.
Card(modifier = modifier) {
   Row(
       modifier = Modifier
           .fillMaxWidth()
           .padding(dimensionResource(id = R.dimen.padding_small))
   ) {
       DogIcon(dog.imageResourceId)
       DogInformation(dog.name, dog.age)
   }
}
  1. Lihat WoofPreview(). Item daftar sekarang telah otomatis berubah warna karena Composable Card. Warnanya terlihat bagus, tetapi tidak ada spasi di antara item daftar.

6d49372a1ef49bc7.png

File dimensi

Sama seperti menggunakan strings.xml untuk menyimpan string di aplikasi Anda, sebaiknya gunakan file bernama dimens.xml untuk menyimpan nilai dimensi. Dengan file ini, Anda tidak perlu melakukan hard code nilai dan jika perlu, Anda dapat mengubahnya di satu tempat.

Buka app > res > values > dimens.xml dan lihat file. Fungsi ini menyimpan nilai dimensi untuk padding_small, padding_medium, dan image_size. Dimensi ini akan digunakan di seluruh aplikasi.

<resources>
   <dimen name="padding_small">8dp</dimen>
   <dimen name="padding_medium">16dp</dimen>
   <dimen name="image_size">64dp</dimen>
</resources>

Untuk menambahkan nilai dari file dimens.xml, ini adalah format yang benar:

Menunjukkan cara memformat penambahan nilai dari resource dimensi dengan benar

Misalnya, untuk menambahkan padding_small, Anda akan meneruskan dimensionResource(id = R.dimen.padding_small).

  1. Di WoofApp(), tambahkan modifier dengan padding_small dalam panggilan ke DogItem().
@Composable
fun WoofApp() {
    Scaffold { it ->
        LazyColumn(contentPadding = it) {
            items(dogs) {
                DogItem(
                    dog = it,
                    modifier = Modifier.padding(dimensionResource(R.dimen.padding_small))
                )
            }
        }
    }
}

Di WoofPreview(), sekarang ada lebih banyak definisi di antara item daftar.

c54f870f121fe02.png

Tema gelap

Di sistem Android, ada opsi untuk mengalihkan perangkat Anda ke tema gelap. Tema gelap menggunakan warna yang lebih gelap, lebih tenang, dan:

  • Dapat mengurangi penggunaan daya secara signifikan (bergantung pada teknologi layar perangkat).
  • Meningkatkan visibilitas bagi pengguna dengan gangguan penglihatan dan mereka yang sensitif terhadap cahaya terang.
  • Memudahkan penggunaan perangkat di lingkungan yang minim cahaya.

Aplikasi Anda dapat ikut serta dalam Gelap Otomatis, yang berarti bahwa sistem akan menerapkan tema gelap untuk Anda. Namun, akan menjadi pengalaman yang lebih baik bagi pengguna jika Anda menerapkan tema gelap, sehingga Anda mempertahankan kontrol penuh atas tema aplikasi.

Saat memilih tema gelap sendiri, penting untuk diperhatikan bahwa warna untuk tema gelap harus memenuhi standar kontras aksesibilitas. Tema gelap menggunakan warna platform gelap, dengan aksen warna terbatas.

Melihat tema gelap dalam pratinjau

Anda telah menambahkan warna untuk tema gelap di langkah sebelumnya. Untuk melihat efek dari tema gelap, Anda dapat menambahkan Composable Pratinjau lainnya ke MainActivity.kt. Dengan demikian, saat mengubah tata letak UI dalam kode, Anda dapat melihat tampilan pratinjau tema terang dan tema gelap secara bersamaan.

  1. Di bagian WoofPreview(), buat fungsi baru bernama WoofDarkThemePreview() dan anotasikan dengan @Preview dan @Composable.
@Preview
@Composable
fun WoofDarkThemePreview() {

}
  1. Di dalam DarkThemePreview(), tambahkan WoofTheme(). Tanpa menambahkan WoofTheme(), Anda tidak akan melihat gaya apa pun yang telah ditambahkan dalam aplikasi. Tetapkan parameter darkTheme ke true.
@Preview
@Composable
fun WoofDarkThemePreview() {
   WoofTheme(darkTheme = true) {

   }
}
  1. Panggil WoofApp() di dalam WoofTheme().
@Preview
@Composable
fun WoofDarkThemePreview() {
   WoofTheme(darkTheme = true) {
       WoofApp()
   }
}

Sekarang, scroll ke bawah di panel Design untuk melihat aplikasi dalam tema gelap, termasuk latar belakang item aplikasi/daftar yang lebih gelap dan teks yang lebih terang. Bandingkan perbedaan antara tema gelap dan terang.

Tema gelap

Tema terang

Melihat tema gelap di perangkat atau emulator

Untuk melihat aplikasi Anda dalam tema gelap di emulator atau perangkat fisik:

  1. Buka aplikasi Setelan di perangkat.
  2. Telusuri Tema Gelap dan klik di dalamnya.
  3. Aktifkan/Nonaktifkan Tema gelap.
  4. Buka kembali aplikasi Woof, dan aplikasi akan muncul dalam tema gelap.

bc31a94207265b08.png

Codelab ini lebih berfokus pada tema terang, jadi sebelum Anda melanjutkan ke aplikasi, nonaktifkan tema gelap.

  1. Buka aplikasi Setelan di perangkat.
  2. Pilih Tampilan.
  3. Nonaktifkan Tema gelap.

Bandingkan tampilan aplikasi di awal bagian versus sekarang. Item dan teks daftar terlihat lebih jelas, dan skema warna lebih menarik secara visual.

Tanpa warna

Dengan warna (tema terang)

Dengan warna (tema gelap)

Warna Dinamis

Material 3 sangat berfokus pada personalisasi pengguna - fitur baru dalam Material 3 adalah Warna Dinamis yang membuat tema untuk aplikasi Anda berdasarkan wallpaper pengguna. Dengan demikian, jika pengguna menyukai warna hijau dan memiliki latar belakang ponsel berwarna biru, aplikasi Woof mereka juga akan berwarna biru untuk mencerminkan hal tersebut. Tema dinamis hanya tersedia di perangkat tertentu yang menjalankan Android 12 dan yang lebih baru.

Tema kustom dapat digunakan untuk aplikasi yang memiliki warna branding yang kuat dan juga perlu diterapkan untuk perangkat yang tidak mendukung tema dinamis sehingga aplikasi Anda masih bertema.

  1. Untuk mengaktifkan warna dinamis, buka Theme.kt dan buka composable WoofTheme(), lalu setel parameter dynamicColor ke benar.
@Composable
fun WoofTheme(
   darkTheme: Boolean = isSystemInDarkTheme(),
   dynamicColor: Boolean = true,
   content: @Composable () -> Unit
)
  1. Untuk mengubah latar belakang perangkat atau emulator, buka Setelan, lalu cari Wallpaper.
  2. Ubah wallpaper ke warna atau sekumpulan warna.
  3. Jalankan ulang aplikasi Anda untuk melihat tema dinamis (perhatikan bahwa perangkat atau emulator Anda harus Android 12+ untuk melihat warna dinamis), jangan ragu untuk mencoba fitur ini dengan wallpaper yang berbeda.

710bd13f6b189dc5.png

  1. Codelab ini berfokus pada tema kustom, jadi nonaktifkan dynamicColor sebelum Anda melanjutkan.
@Composable
fun WoofTheme(
   darkTheme: Boolean = isSystemInDarkTheme(),
   dynamicColor: Boolean = false,
   content: @Composable () -> Unit
)

5. Menambahkan bentuk

Menerapkan bentuk akan sangat memengaruhi tampilan dan nuansa composable. Bentuk mampu menarik perhatian, mengidentifikasi komponen, mengomunikasikan status, dan mengekspresikan merek.

Banyak bentuk ditentukan menggunakan RoundedCornerShape, yang menggambarkan persegi panjang dengan sudut membulat. Angka yang diteruskan menentukan kebulatan sudut. Jika RoundedCornerShape(0.dp) digunakan, persegi panjang tidak memiliki sudut membulat; jika RoundedCornerShape(50.dp) digunakan, sudut akan membulat sepenuhnya.

0.dp

25.dp

50.dp

Item daftar Woof dengan pembentukan

Item daftar Woof dengan pembentukan

Item daftar Woof dengan pembentukan

Anda juga dapat menyesuaikan bentuk lebih lanjut dengan menambahkan berbagai persentase pembulatan pada setiap sudut. Sangat menyenangkan bermain dengan bentuk!

Kiri atas: 50.dp
Kiri bawah: 25.dp
Kanan atas: 0.dp
Kanan bawah: 15.dp

Kiri atas: 15.dp
Kiri bawah: 50.dp
Kanan atas: 50.dp
Kanan bawah: 15.dp

Kiri atas: 0.dp
Kiri bawah: 50.dp
Kanan atas: 0.dp
Kanan bawah: 50.dp

Item daftar Woof dengan pembentukan

Item daftar Woof dengan pembentukan

Item daftar Woof dengan pembentukan

File Shape.kt digunakan untuk menentukan bentuk komponen di Compose. Ada tiga jenis komponen: kecil, sedang, dan besar. Di bagian ini, Anda akan mengubah komponen Card, yang ditentukan sebagai ukuran medium. Komponen dikelompokkan ke dalam kategori bentuk berdasarkan ukurannya.

Pada bagian ini, Anda akan membentuk gambar anjing menjadi lingkaran, dan mengubah bentuk item daftar.

Membentuk gambar anjing menjadi lingkaran

  1. Buka file Shape.kt dan perhatikan bahwa parameter kecil ditetapkan ke RoundedCornerShape(50.dp). Ini akan digunakan untuk membentuk gambar menjadi lingkaran.
val Shapes = Shapes(
   small = RoundedCornerShape(50.dp),
)
  1. Buka MainActivity.kt. Di DogIcon(), tambahkan atribut clip ke modifier dari Image; tindakan ini akan memotong gambar menjadi sebuah bentuk. Teruskan MaterialTheme.shapes.small.
import androidx.compose.ui.draw.clip

@Composable
fun DogIcon(
   @DrawableRes dogIcon: Int,
   modifier: Modifier = Modifier
) {
   Image(
       modifier = modifier
           .size(dimensionResource(id = R.dimen.image_size))
           .padding(dimensionResource(id = R.dimen.padding_small))
           .clip(MaterialTheme.shapes.small),

Saat melihat WoofPreview(), Anda akan melihat ikon anjing tersebut menjadi lingkaran. Namun, beberapa foto terpotong di bagian samping dan tidak muncul sebagai lingkaran sepenuhnya.

1d4d1e5eaaddf71e.png

  1. Untuk membuat semua foto menjadi lingkaran, tambahkan atribut ContentScale dan Crop; tindakan ini akan memangkas gambar agar sesuai. Perlu diketahui bahwa contentScale adalah atribut dari Image, dan bukan bagian dari modifier.
import androidx.compose.ui.layout.ContentScale

@Composable
fun DogIcon(
   @DrawableRes dogIcon: Int,
   modifier: Modifier = Modifier
) {
   Image(
       modifier = modifier
           .size(dimensionResource(id = R.dimen.image_size))
           .padding(dimensionResource(id = R.dimen.padding_small))
           .clip(MaterialTheme.shapes.small),
       contentScale = ContentScale.Crop,

Ini adalah Composable DogIcon() lengkap.

@Composable
fun DogIcon(
    @DrawableRes dogIcon: Int,
    modifier: Modifier = Modifier
) {
    Image(
        modifier = modifier
            .size(dimensionResource(R.dimen.image_size))
            .padding(dimensionResource(R.dimen.padding_small))
            .clip(MaterialTheme.shapes.small),
        contentScale = ContentScale.Crop,
        painter = painterResource(dogIcon),

        // Content Description is not needed here - image is decorative, and setting a null content
        // description allows accessibility services to skip this element during navigation.

        contentDescription = null
    )
}

Sekarang di WoofPreview(), ikon berbentuk lingkaran.

fc93106990f5e161.png

Menambahkan bentuk ke item daftar

Di bagian ini, Anda akan menambahkan bentuk ke item daftar. Item daftar sudah ditampilkan melalui Card. Card adalah platform yang dapat berisi satu composable dan berisi opsi untuk dekorasi. Dekorasi dapat ditambahkan melalui batas, bentuk, dan lainnya. Di bagian ini, Anda akan menggunakan Card untuk menambahkan bentuk ke item daftar.

Item daftar Woof dengan dimensi bentuk yang ditambahkan

  1. Buka file Shape.kt. Card adalah komponen media, sehingga Anda menambahkan parameter media objek Shapes. Untuk aplikasi ini, pojok kanan atas dan kiri bawah item daftar, tetapi tidak membentuk lingkaran penuh. Untuk mencapainya, teruskan 16.dp ke atribut medium.
medium = RoundedCornerShape(bottomStart = 16.dp, topEnd = 16.dp)

Karena Card secara default sudah menggunakan bentuk media, Anda tidak perlu menyetelnya secara eksplisit ke bentuk media. Lihat Pratinjau untuk melihat Card yang baru dibentuk.

Pratinjau Woof dengan kartu berbentuk

Jika kembali ke file Theme.kt di WoofTheme() dan melihat MaterialTheme(), Anda akan melihat atribut shapes disetel ke Shapes val yang baru saja Anda update.

MaterialTheme(
   colors = colors,
   typography = Typography,
   shapes = Shapes,
   content = content
)

Berikut adalah tampilan item daftar secara berdampingan sebelum dan sesudah pembentukan. Perhatikan bahwa aplikasi ini menjadi jauh lebih menarik secara visual dengan pembentukan yang ditambahkan padanya.

Tanpa pembentukan

Dengan pembentukan

6. Menambahkan tipografi

Jenis huruf Desain Material

Jenis huruf adalah pilihan gaya font yang dapat digunakan di seluruh aplikasi dan memastikan gaya yang fleksibel namun konsisten. Jenis huruf Desain Material mencakup lima belas gaya font yang didukung oleh sistem jenis. Penamaan dan pengelompokannya telah disederhanakan untuk: tampilan, judul utama, judul, isi, dan label, dengan ukuran besar, sedang, dan kecil untuk masing-masing. Anda hanya perlu menggunakan pilihan ini jika ingin menyesuaikan aplikasi. Jika Anda tidak tahu apa yang harus ditetapkan untuk setiap kategori jenis huruf, ada skala tipografi default yang dapat Anda gunakan.

999a161dcd9b0ec4.png

Jenis huruf ini berisi kategori teks yang dapat digunakan kembali, masing-masing dengan aplikasi yang dimaksudkan dan artinya.

Tampilan

Sebagai teks terbesar di layar, gaya tampilan dikhususkan untuk teks atau angka yang singkat dan penting. Gaya tampilan berfungsi paling baik di perangkat layar besar.

Judul Utama

Judul utama sangat cocok untuk teks singkat dengan penekanan tinggi pada layar yang lebih kecil. Gaya ini cocok untuk menandai bagian utama teks atau area penting konten.

Judul

Judul lebih kecil daripada gaya judul utama, dan harus digunakan untuk teks dengan penekanan sedang yang relatif singkat.

Isi

Gaya isi digunakan untuk bagian teks yang lebih panjang di aplikasi Anda.

Label

Gaya label adalah gaya yang lebih kecil dan fungsional, yang digunakan untuk hal-hal seperti teks di dalam komponen atau untuk teks yang sangat kecil di dalam isi konten, misalnya keterangan gambar.

Font

Platform Android menyediakan berbagai font, tetapi Anda mungkin ingin menyesuaikan aplikasi dengan font yang tidak disediakan secara default. Font kustom dapat menambah karakteristik dan digunakan untuk branding.

Di bagian ini, Anda akan menambahkan font khusus bernama Abril Fatface, Montserrat Bold, dan Montserrat Regular. Anda akan menggunakan judul utama displayLarge dan displayMedium, juga teks bodyLarge dari sistem Jenis Material, dan menambahkannya ke teks di aplikasi Anda.

Membuat Direktori Resource Android font.

Sebelum menambahkan font ke aplikasi, Anda harus menambahkan direktori font.

  1. Di tampilan project Android Studio, klik kanan folder res.
  2. Pilih New > Android Resource Directory.

Gambar ini menunjukkan navigasi struktur file ke Direktori Resource Android.

  1. Beri nama Direktori font, setel jenis Resource sebagai font, dan klik OK.

Gambar ini menunjukkan penambahan direktori font menggunakan Direktori Resource Baru.

  1. Buka direktori resource font baru yang terletak di res > font.

Mendownload font kustom

Karena Anda menggunakan font yang tidak disediakan oleh platform Android, Anda harus mendownload font kustom.

  1. Buka https://fonts.google.com/.
  2. Telusuri Montserrat, lalu klik Download family.
  3. Buka file zip.
  4. Buka folder Montserrat yang didownload. Di folder static, temukan Montserrat-Bold.ttf dan Montserrat-Regular.ttf (ttf adalah singkatan dari TrueType Font dan merupakan format untuk file font). Pilih kedua font dan tarik ke direktori resource font dalam project Anda di Android Studio.

Gambar ini menampilkan konten folder statis font Montserrat.

  1. Di folder font, ganti nama Montserrat-Bold.ttf menjadi montserrat_bold.ttf dan ganti nama Montserrat-Regular.ttf menjadi montserrat_regular.ttf.
  2. Telusuri Abril Fatface dan klik Download family.
  3. Buka folder Abril_Fatface yang telah didownload. Pilih AbrilFatface-Regular.ttf, lalu tarik ke direktori resource font.
  4. Di folder font, ganti nama Abril_Fatface_Regular.ttf menjadi abril_fatface_regular.ttf.

Seperti inilah tampilan direktori resource font dalam project Anda dengan tiga file font kustom:

Gambar ini menampilkan file font yang ditambahkan ke folder font.

Melakukan inisialisasi font

  1. Di jendela project, buka ui.theme > Type.kt. Lakukan inisialisasi font yang didownload di bawah pernyataan impor dan di atas Typography val. Pertama, lakukan inisialisasi Abril Fatface dengan menyetelnya sama dengan FontFamily dan meneruskan Font dengan file font abril_fatface_regular.
​​import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import com.example.woof.R

val AbrilFatface = FontFamily(
   Font(R.font.abril_fatface_regular)
)
  1. Lakukan inisialisasi Montserrat, di bawah Abril Fatface, dengan menyetelnya sama dengan FontFamily dan meneruskan Font dengan file font montserrat_regular. Untuk montserrat_bold, sertakan juga FontWeight.Bold. Meskipun Anda meneruskan file font versi cetak tebal, Compose tidak mengetahui bahwa file tersebut dicetak tebal, jadi Anda perlu menautkan file secara eksplisit ke FontWeight.Bold.
import androidx.compose.ui.text.font.FontWeight

val AbrilFatface = FontFamily(
   Font(R.font.abril_fatface_regular)
)

val Montserrat = FontFamily(
   Font(R.font.montserrat_regular),
   Font(R.font.montserrat_bold, FontWeight.Bold)
)

Selanjutnya, Anda menetapkan berbagai jenis judul ke font yang baru saja Anda tambahkan. Objek Typography memiliki parameter untuk 13 jenis huruf berbeda yang dibahas di atas. Anda dapat menentukan sebanyak yang Anda butuhkan. Dalam aplikasi ini, kita akan menetapkan displayLarge, displayMedium, dan bodyLarge. Di bagian berikutnya dari aplikasi ini, Anda akan menggunakan labelSmall, sehingga Anda akan menambahkannya di sini.

Di bawah ini adalah tabel yang menampilkan jenis font, ketebalan, dan ukuran dari setiap judul utama yang Anda tambahkan.

8ea685b3871d5ffc.png

  1. Untuk atribut displayLarge, tetapkan sama dengan TextStyle, lalu isi fontFamily, fontWeight, dan fontSize dengan informasi dari tabel di atas. Artinya, semua teks yang ditetapkan ke displayLarge akan memiliki Abril Fatface sebagai font, dengan ketebalan font normal, dan fontSize 36.sp.

Ulangi proses ini untuk displayMedium, labelSmall, dan bodyLarge.

import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.sp

val Typography = Typography(
   displayLarge = TextStyle(
       fontFamily = AbrilFatface,
       fontWeight = FontWeight.Normal,
       fontSize = 36.sp
   ),
   displayMedium = TextStyle(
       fontFamily = Montserrat,
       fontWeight = FontWeight.Bold,
       fontSize = 20.sp
   ),
   labelSmall = TextStyle(
       fontFamily = Montserrat,
       fontWeight = FontWeight.Bold,
       fontSize = 14.sp
   ),
   bodyLarge = TextStyle(
       fontFamily = Montserrat,
       fontWeight = FontWeight.Normal,
       fontSize = 14.sp
   )
)

Jika Anda membuka file Theme.kt di WoofTheme() dan melihat MaterialTheme(), parameter typography sama dengan Typography val yang baru saja Anda update.

MaterialTheme(
   colors = colors,
   typography = Typography,
   shapes = Shapes,
   content = content
)

Menambahkan tipografi ke teks aplikasi

Sekarang Anda akan menambahkan jenis judul utama ke setiap instance teks di aplikasi.

  1. Tambahkan displayMedium sebagai gaya untuk dogName karena merupakan informasi singkat yang penting. Tambahkan bodyLarge sebagai gaya untuk dogAge karena berfungsi cukup baik dengan ukuran teks yang lebih kecil.
@Composable
fun DogInformation(
   @StringRes dogName: Int,
   dogAge: Int,
   modifier: Modifier = Modifier
) {
   Column(modifier = modifier) {
       Text(
           text = stringResource(dogName),
           style = MaterialTheme.typography.displayMedium,
           modifier = Modifier.padding(top = dimensionResource(id = R.dimen.padding_small))
       )
       Text(
           text = stringResource(R.string.years_old, dogAge),
           style = MaterialTheme.typography.bodyLarge
       )
   }
}
  1. Sekarang di WoofPreview(), nama anjing akan menampilkan font Montserrat tebal dalam 20.sp, dan usia anjing menampilkan font Montserrat normal dalam 14.sp.

Pratinjau Woof dengan tipografi ditambahkan

Berikut ini tampilan item daftar secara berdampingan sebelum dan sesudah menambahkan tipografi. Perhatikan perbedaan font antara nama anjing dan usia anjing.

Tanpa tipografi

Dengan tipografi

7. Menambahkan panel atas

Scaffold adalah tata letak yang menyediakan slot untuk berbagai komponen dan elemen layar, seperti Image, Row, atau Column. Scaffold juga menyediakan slot untuk TopAppBar, yang akan Anda gunakan di bagian ini.

TopAppBar dapat digunakan untuk berbagai tujuan, tetapi dalam hal ini, Anda akan menggunakannya untuk branding dan memberikan karakteristik pada aplikasi. Ada empat jenis TopAppBar: tengah, kecil, sedang, dan besar. Dalam codelab ini, Anda akan menerapkan panel aplikasi atas di tengah. Anda akan membuat composable yang terlihat seperti screenshot di bawah, dan memasukkannya ke bagian topBar dari Scaffold.

172417c7b64372f7.png

Untuk aplikasi ini, panel atas terdiri dari Row dengan gambar logo dan teks judul aplikasi. Logo menampilkan tapak kaki bergradasi yang lucu dan judul aplikasi!

736f411f5067e0b5.png

Menambahkan gambar dan teks ke panel atas

  1. Di MainActivity.kt, buat composable bernama WoofTopAppBar() dengan modifier opsional.
@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier) {

}
  1. Scaffold mendukung parameter contentWindowInsets yang dapat membantu menentukan inset untuk konten scaffold. WindowInsets adalah bagian layar tempat aplikasi Anda dapat bersinggungan dengan UI sistem, yang akan diteruskan ke slot konten melalui parameter PaddingValues. Baca selengkapnya di sini.

Nilai contentWindowInsets diteruskan ke LazyColumn sebagai contentPadding.

@Composable
fun WoofApp() {
    Scaffold { it ->
        LazyColumn(contentPadding = it) {
            items(dogs) {
                DogItem(
                    dog = it,
                    modifier = Modifier.padding(dimensionResource(R.dimen.padding_small))
                )
            }
        }
    }
}
  1. Dalam Scaffold, tambahkan atribut topBar dan tetapkan ke WoofTopAppBar().
Scaffold(
   topBar = {
       WoofTopAppBar()
   }
)

Berikut adalah tampilan composable WoofApp():

@Composable
fun WoofApp() {
    Scaffold(
        topBar = {
            WoofTopAppBar()
        }
    ) { it ->
        LazyColumn(contentPadding = it) {
            items(dogs) {
                DogItem(
                    dog = it,
                    modifier = Modifier.padding(dimensionResource(R.dimen.padding_small))
                )
            }
        }
    }
}

Tidak ada yang berubah di WoofPreview() karena tidak ada apa pun di WoofTopAppBar(). Mari kita ubah.

Pratinjau Woof dengan tipografi

  1. Dalam WoofTopAppBar() Composable, tambahkan CenterAlignedTopAppBar() dan tetapkan parameter pengubah ke pengubah yang diteruskan ke WoofTopAppBar().
import androidx.compose.material3.CenterAlignedTopAppBar

@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier) {
   CenterAlignedTopAppBar(
       modifier = modifier
   )
}
  1. Untuk parameter judul, teruskan Row yang akan menyimpan Image dan Text dari CenterAlignedTopAppBar.
@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier){
   CenterAlignedTopAppBar(
       title = {
           Row() {

           }
       },
       modifier = modifier
   )
}
  1. Tambahkan logo Image ke Row.
  • Setel ukuran gambar di modifier sebagai image_size dalam file dimens.xml dan padding sebagai padding_small dari file dimens.xml.
  • Gunakan painter untuk menetapkan Image sebagai ic_woof_logo dari folder drawable.
  • Tetapkan contentDescription sebagai null. Dalam situasi ini, logo aplikasi tidak menambahkan informasi semantik apa pun bagi pengguna dengan gangguan penglihatan, sehingga kita tidak perlu menambahkan deskripsi konten.
Row() {
   Image(
       modifier = Modifier
           .size(dimensionResource(id = R.dimen.image_size))
           .padding(dimensionResource(id = R.dimen.padding_small)),
       painter = painterResource(R.drawable.ic_woof_logo),
       contentDescription = null
   )
}
  1. Selanjutnya, tambahkan Composable Text di dalam Row setelah Image.
  • Gunakan stringResource() untuk menetapkannya ke nilai app_name. Tindakan ini akan menetapkan teks ke nama aplikasi, yang disimpan di strings.xml.
  • Setel gaya teks ke displayLarge karena nama aplikasi singkat dan penting.
Text(
   text = stringResource(R.string.app_name),
   style = MaterialTheme.typography.displayLarge
)

Pratinjau Woof dengan panel aplikasi atas

Inilah yang muncul di WoofPreview(), dan terlihat sedikit tidak rapi karena ikon dan teks tidak sejajar secara vertikal.

  1. Untuk memperbaikinya, tambahkan parameter nilai verticalAlignment ke Row dan tetapkan sama dengan Alignment.CenterVertically.
import androidx.compose.ui.Alignment

Row(
   verticalAlignment = Alignment.CenterVertically
)

Pratinjau Woof dengan panel aplikasi atas yang diletakkan di tengah secara vertikal

Itu terlihat jauh lebih baik.

Ini adalah Composable WoofTopAppBar() lengkap:

@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier) {
   CenterAlignedTopAppBar(
       title = {
           Row(
               verticalAlignment = Alignment.CenterVertically
           ) {
               Image(
                   modifier = Modifier
                       .size(dimensionResource(id = R.dimen.image_size))
                       .padding(dimensionResource(id = R.dimen.padding_small)),
                   painter = painterResource(R.drawable.ic_woof_logo),

                   contentDescription = null
               )
               Text(
                   text = stringResource(R.string.app_name),
                   style = MaterialTheme.typography.displayLarge
               )
           }
       },
       modifier = modifier
   )
}

Jalankan aplikasi dan lihat betapa indahnya TopAppBar memadukan aplikasi.

Tanpa panel aplikasi atas

Dengan panel aplikasi atas

Sekarang, lihat aplikasi final dalam tema gelap.

2776e6a45cf3434a.png

Selamat, Anda berhasil sampai ke akhir codelab!

8. Mendapatkan kode solusi

Untuk mendownload kode codelab yang sudah selesai, Anda dapat menggunakan perintah git berikut:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-woof.git
$ cd basic-android-kotlin-compose-training-woof
$ git checkout material

Atau, Anda dapat mendownload repositori sebagai file ZIP, lalu mengekstraknya, dan membukanya di Android Studio.

Jika Anda ingin melihat kode solusi, lihat di GitHub.

9. Kesimpulan

Anda baru saja membuat aplikasi Material pertama Anda! Anda membuat palet warna kustom untuk tema terang dan gelap, membuat bentuk untuk berbagai komponen, mendownload font dan menambahkannya ke aplikasi, lalu membuat panel atas yang menarik untuk menyatukan semuanya. Tingkatkan keterampilan yang Anda pelajari dalam codelab ini dan ubah warna, bentuk, serta tipografi agar aplikasi menjadi kreasi Anda sendiri sepenuhnya!

Ringkasan

  • Penerapan Tema Material memungkinkan Anda menggunakan Desain Material di aplikasi, dengan panduan tentang penyesuaian warna, tipografi, dan bentuk.
  • File Theme.kt adalah tempat tema ditetapkan, melalui composable bernama [your app name]+Theme()WoofTheme() dalam kasus aplikasi ini. Dalam fungsi ini, objek MaterialTheme menetapkan color, typography, shapes, dan content aplikasi.
  • Color.kt adalah tempat Anda mencantumkan warna yang digunakan dalam aplikasi. Kemudian di Theme.kt, Anda menetapkan warna dalam LightColorPalette dan DarkColorPalette ke slot tertentu. Tidak semua slot harus ditetapkan.
  • Aplikasi Anda dapat ikut serta dalam Gelap Otomatis, yang berarti bahwa sistem akan menerapkan tema gelap untuk Anda. Namun, akan menjadi pengalaman yang lebih baik bagi pengguna jika Anda menerapkan tema gelap sehingga Anda memiliki kontrol penuh atas tema aplikasi.
  • Shape.kt adalah tempat Anda menentukan bentuk aplikasi. Ada tiga ukuran bentuk (kecil, sedang, besar), dan Anda dapat menentukan bagaimana sudut dibulatkan.
  • Bentuk mampu menarik perhatian, mengidentifikasi komponen, mengomunikasikan status, dan mengekspresikan merek.
  • Type.kt adalah tempat Anda melakukan inisialisasi font dan menetapkan fontFamily, fontWeight, dan fontSize untuk jenis huruf Desain Material.
  • Jenis huruf Desain Material mencakup berbagai gaya kontras yang mendukung kebutuhan aplikasi Anda dan kontennya. Jenis huruf adalah kombinasi dari 15 gaya yang didukung oleh sistem jenis.

10. Mempelajari lebih lanjut