1. Pengantar
Dalam codelab ini, Anda akan mempelajari cara menggunakan API tema Jetpack Compose untuk memberi gaya pada aplikasi Anda. Kita akan melihat cara menyesuaikan warna, bentuk, dan tipografi agar digunakan secara konsisten di seluruh aplikasi Anda, yang mendukung beberapa tema seperti tema terang & gelap.
Yang akan Anda pelajari
Dalam codelab ini, Anda akan mempelajari:
- Pedoman dasar Desain Material dan cara menyesuaikannya untuk merek Anda
- Cara Compose menerapkan sistem Desain Material
- Cara menentukan dan menggunakan warna, tipografi, dan bentuk di seluruh aplikasi
- Cara mengatur gaya komponen
- Cara mendukung tema terang dan gelap
Yang akan Anda build
Dalam codelab ini, kita akan mengatur gaya aplikasi pembacaan berita. Kita memulai dengan aplikasi tanpa gaya dan akan menerapkan apa yang kita pelajari untuk memberi tema aplikasi dan mendukung tema gelap.
Sebelum: aplikasi tanpa gaya | Sesudah: aplikasi yang diberi gaya | Sesudah: tema gelap |
Prasyarat
- Pengalaman dengan sintaksis Kotlin, termasuk lambda
- Pemahaman dasar tentang Compose.
- Pemahaman dasar tentang Tata letak Compose, mis.
Row
,Column
, &Modifier
2. Mempersiapkan
Pada langkah ini, Anda akan mendownload kode yang terdiri dari aplikasi pembaca berita sederhana yang akan kita beri gaya.
Yang akan Anda butuhkan
Mendownload kode
Jika sudah menginstal git, Anda cukup menjalankan perintah di bawah. Untuk memeriksa apakah git sudah diinstal, ketik git --version
di terminal atau command line dan pastikan git dijalankan dengan benar.
git clone https://github.com/googlecodelabs/android-compose-codelabs.git cd android-compose-codelabs/ThemingCodelabM2
Jika tidak memiliki git, Anda dapat mengklik tombol berikut untuk mendownload semua kode untuk codelab ini:
Buka project di Android Studio, lalu pilih 'File > Import Project' dan cari direktori ThemingCodelabM2
.
Project ini berisi tiga paket utama:
com.codelab.theming.data
Ini berisi class model dan data contoh. Anda tidak perlu mengedit paket ini selama codelab ini.com.codelab.theming.ui.start
Ini adalah titik awal codelab, Anda harus membuat semua perubahan yang diminta dalam codelab ini dalam paket ini.com.codelab.theming.ui.finish
Ini adalah status akhir codelab, untuk referensi Anda.
Membuat dan menjalankan aplikasi
Aplikasi ini memiliki 2 konfigurasi run yang mencerminkan status awal dan akhir codelab. Memilih salah satu konfigurasi dan menekan tombol run akan men-deploy kode ke perangkat atau emulator Anda.
Aplikasi juga berisi Pratinjau tata letak Compose. Penjelajahan ke Home.kt
dalam paket start
/finish
dan membuka tampilan desain menunjukkan sejumlah pratinjau yang memungkinkan iterasi cepat pada kode UI Anda:
3. Penerapan Tema Material
Jetpack Compose menawarkan implementasi Desain Material—sistem desain komprehensif untuk membuat antarmuka digital. Komponen Desain Material (Tombol, Kartu, Tombol Akses, dll.) dibuat di atas Tema Material yang merupakan cara sistematis untuk menyesuaikan Desain Material agar lebih mencerminkan merek produk Anda. Tema Material terdiri dari atribut warna, tipografi, dan bentuk. Penyesuain atribut tersebut akan secara otomatis tercermin dalam komponen yang Anda gunakan untuk membuat aplikasi.
Pemahaman tentang Penerapan Tema Material berguna untuk memahami cara memberi tema aplikasi Jetpack Compose, jadi berikut adalah deskripsi singkat konsepnya. Jika sudah memahami Penerapan Tema Material, Anda dapat melewatinya.
Warna
Desain Material menentukan sejumlah warna yang dinamai secara semantik yang dapat Anda gunakan di seluruh aplikasi:
Warna primer adalah warna merek utama Anda dan warna sekunder digunakan untuk memberikan aksen. Anda dapat menyediakan varian yang lebih gelap/lebih terang untuk area yang kontras. Warna latar belakang dan permukaan digunakan untuk penampung yang menyimpan komponen yang pada prinsipnya berada di "permukaan" dalam aplikasi Anda. Material juga mendefinisikan warna "aktif"—warna yang akan digunakan untuk konten selain salah satu warna yang diberi nama, misalnya teks, dalam penampung berwarna 'permukaan' harus diberi warna 'di permukaan'. Komponen material dikonfigurasi untuk menggunakan warna tema ini, misalnya secara default Tombol Tindakan Mengambang (FAB) diberi warna secondary
, Kartu ditetapkan secara default ke surface
, dll.
Dengan menentukan warna yang diberi nama, Anda dapat menyediakan palet warna alternatif seperti tema terang dan gelap:
Fitur ini juga mendorong Anda untuk menentukan palet warna kecil dan menggunakannya secara konsisten di seluruh aplikasi. Alat warna Material dapat membantu memilih warna dan membuat palet warna, bahkan memastikan bahwa kombinasi bisa dilakukan.
Tipografi
Demikian pula, Material menentukan sejumlah gaya tulisan yang dinamai secara semantik:
Meskipun Anda tidak dapat memvariasikan gaya tulisan berdasarkan tema, penggunaan skala tulisan akan mendorong konsistensi dalam aplikasi Anda. Menyediakan font Anda sendiri dan penyesuaian jenis lainnya akan tercermin dalam komponen Material yang Anda gunakan dalam aplikasi, mis. Panel Aplikasi menggunakan gaya h6
secara default, Tombol menggunakan gaya, err, button
. Alat generator skala tulisan Material dapat membantu Anda membuat skala tulisan.
Bentuk
Material mendukung penggunaan bentuk secara sistematis untuk menyampaikan merek Anda. Terdapat 3 kategori: komponen kecil, sedang, dan besar; yang masing-masing dapat menentukan bentuk yang akan digunakan, menyesuaikan gaya sudut (terpotong atau membulat) dan ukuran.
Penyesuaian tema bentuk akan tercermin di berbagai komponen, mis. Tombol & Kolom Teks menggunakan tema bentuk kecil, Kartu dan Dialog menggunakan tema bentuk medium, dan Spreadsheet menggunakan tema bentuk besar secara default. Pemetaan lengkap komponen untuk tema bentuk tersedia di sini. Alat penyesuaian bentuk Material dapat membantu Anda membuat tema bentuk.
Tema dasar bawaan
Material ditetapkan secara default ke tema "dasar bawaan", yaitu skema warna ungu, skala tulisan Roboto, dan bentuk yang sedikit membulat yang terlihat pada gambar di atas. Jika Anda tidak menentukan atau menyesuaikan tema, komponen akan menggunakan tema dasar bawaan.
4. Menentukan tema Anda
MaterialTheme
Elemen inti untuk menerapkan tema ke Jetpack Compose adalah composable MaterialTheme
. Menempatkan composable ini dalam hierarki compose memungkinkan Anda menentukan penyesuaian warna, jenis, dan bentuk untuk semua komponen di dalamnya. Berikut adalah cara menentukan composable ini di library:
@Composable
fun MaterialTheme(
colors: Colors,
typography: Typography,
shapes: Shapes,
content: @Composable () -> Unit
) { ...
Kemudian, Anda dapat mengambil parameter yang diteruskan ke composable ini menggunakan MaterialTheme
object
, yang mengekspos properti colors
, typography
, dan shapes
. Kita akan membahas masing-masing detail tersebut lebih jauh nanti.
Buka Home.kt
dan cari fungsi composable Home
— ini adalah titik entri utama untuk aplikasi. Perhatikan bahwa saat mendeklarasikan MaterialTheme
, kita tidak menentukan parameter apa pun sehingga menerima gaya "dasar bawaan" default:
@Composable
fun Home() {
...
MaterialTheme {
Scaffold(...
Mari kita buat parameter warna, jenis, dan bentuk untuk menerapkan tema aplikasi.
Membuat Tema
Untuk memusatkan gaya Anda, sebaiknya buat composable Anda sendiri yang menggabungkan dan mengonfigurasi MaterialTheme
. Ini memberi Anda satu tempat untuk menentukan penyesuaian tema dan memungkinkan Anda menggunakannya kembali dengan mudah di banyak tempat, misalnya di beberapa layar atau @Preview
. Anda dapat membuat beberapa composable tema jika diperlukan, misalnya jika ingin mendukung gaya yang lain untuk bagian yang berbeda dari aplikasi Anda.
Dalam paket com.codelab.theming.ui.start.theme
, buat file Kotlin baru bernama Theme.kt
. Tambahkan fungsi composable baru yang disebut JetnewsTheme
, yang menerima composable lain sebagai konten dan menggabungkan MaterialTheme
:
@Composable
fun JetnewsTheme(content: @Composable () -> Unit) {
MaterialTheme(content = content)
}
Sekarang beralih kembali ke Home.kt
dan ganti MaterialTheme
dengan JetnewsTheme
kita (dan impor):
- MaterialTheme {
+ JetnewsTheme {
...
Anda belum akan melihat perubahan apa pun di @Preview
pada layar ini. Perbarui PostItemPreview
dan FeaturedPostPreview
untuk menggabungkan kontennya dengan composable JetnewsTheme
baru sehingga pratinjau menggunakan tema baru:
@Preview("Featured Post")
@Composable
private fun FeaturedPostPreview() {
val post = remember { PostRepo.getFeaturedPost() }
+ JetnewsTheme {
FeaturedPost(post = post)
+ }
}
Warna
Berikut palet warna yang ingin kita terapkan di aplikasi (hanya palet terang untuk saat ini, kita akan kembali untuk mendukung tema gelap segera):
Warna di Compose ditentukan menggunakan class Color
. Ada beberapa konstruktor yang memungkinkan Anda menentukan warna sebagai ULong
atau dengan saluran warna terpisah.
Buat file baru Color.kt
di paket theme
Anda. Tambahkan warna berikut sebagai properti publik tingkat atas dalam file ini:
val Red700 = Color(0xffdd0d3c)
val Red800 = Color(0xffd00036)
val Red900 = Color(0xffc20029)
Setelah menentukan warna aplikasi, mari gabungkan warna tersebut ke dalam objek Colors
yang diperlukan MaterialTheme
, yang menetapkan warna tertentu ke warna Material yang dinamai. Beralih kembali ke Theme.kt
dan tambahkan berikut ini:
private val LightColors = lightColors(
primary = Red700,
primaryVariant = Red900,
onPrimary = Color.White,
secondary = Red700,
secondaryVariant = Red900,
onSecondary = Color.White,
error = Red800
)
Di sini kita menggunakan fungsi lightColors
untuk membuat Colors
, hal ini memberikan default yang masuk akal sehingga kita tidak perlu menentukan semua warna yang membentuk palet warna Material. Misalnya, perhatikan bahwa kita belum menentukan warna background
atau banyak warna 'aktif', kita akan menggunakan warna default.
Sekarang, mari kita gunakan warna ini dalam aplikasi. Perbarui composable JetnewsTheme
untuk menggunakan Colors
baru kita:
@Composable
fun JetnewsTheme(content: @Composable () -> Unit) {
MaterialTheme(
+ colors = LightColors,
content = content
)
}
Buka Home.kt
dan muat ulang pratinjau. Perhatikan skema warna baru yang ditampilkan dalam komponen seperti TopAppBar
.
Tipografi
Berikut adalah skala tulisan yang ingin kita implementasikan di aplikasi:
Di Compose, kita dapat menentukan objek TextStyle
untuk menentukan informasi yang diperlukan untuk memberi gaya beberapa teks. Contoh atributnya:
data class TextStyle(
val color: Color = Color.Unset,
val fontSize: TextUnit = TextUnit.Inherit,
val fontWeight: FontWeight? = null,
val fontStyle: FontStyle? = null,
val fontFamily: FontFamily? = null,
val letterSpacing: TextUnit = TextUnit.Inherit,
val background: Color = Color.Unset,
val textAlign: TextAlign? = null,
val textDirection: TextDirection? = null,
val lineHeight: TextUnit = TextUnit.Inherit,
...
)
Skala tulisan yang kita inginkan menggunakan Montserrat untuk judul dan Domine untuk teks isi. File font yang relevan sudah ditambahkan ke folder res/fonts
project Anda.
Buat file baru Typography.kt
dalam paket theme
. Mari kita tentukan terlebih dahulu FontFamily
(yang menggabungkan bobot yang berbeda dari setiap Font
):
private val Montserrat = FontFamily(
Font(R.font.montserrat_regular),
Font(R.font.montserrat_medium, FontWeight.W500),
Font(R.font.montserrat_semibold, FontWeight.W600)
)
private val Domine = FontFamily(
Font(R.font.domine_regular),
Font(R.font.domine_bold, FontWeight.Bold)
)
Sekarang, buat objek Typography
yang diterima MaterialTheme
, dengan menentukan TextStyle
untuk setiap gaya semantik dalam skala:
val JetnewsTypography = Typography(
h4 = TextStyle(
fontFamily = Montserrat,
fontWeight = FontWeight.W600,
fontSize = 30.sp
),
h5 = TextStyle(
fontFamily = Montserrat,
fontWeight = FontWeight.W600,
fontSize = 24.sp
),
h6 = TextStyle(
fontFamily = Montserrat,
fontWeight = FontWeight.W600,
fontSize = 20.sp
),
subtitle1 = TextStyle(
fontFamily = Montserrat,
fontWeight = FontWeight.W600,
fontSize = 16.sp
),
subtitle2 = TextStyle(
fontFamily = Montserrat,
fontWeight = FontWeight.W500,
fontSize = 14.sp
),
body1 = TextStyle(
fontFamily = Domine,
fontWeight = FontWeight.Normal,
fontSize = 16.sp
),
body2 = TextStyle(
fontFamily = Montserrat,
fontSize = 14.sp
),
button = TextStyle(
fontFamily = Montserrat,
fontWeight = FontWeight.W500,
fontSize = 14.sp
),
caption = TextStyle(
fontFamily = Montserrat,
fontWeight = FontWeight.Normal,
fontSize = 12.sp
),
overline = TextStyle(
fontFamily = Montserrat,
fontWeight = FontWeight.W500,
fontSize = 12.sp
)
)
Buka Theme.kt
dan perbarui composable JetnewsTheme
untuk menggunakan Typography
baru kita:
@Composable
fun JetnewsTheme(content: @Composable () -> Unit) {
MaterialTheme(
colors = LightColors,
+ typography = JetnewsTypography,
content = content
)
}
Buka Home.kt
dan muat ulang pratinjau untuk melihat penerapan tipografi baru.
Bentuk
Kita ingin menggunakan bentuk untuk mengekspresikan merek di aplikasi. Kita ingin menggunakan bentuk sudut terpotong pada sejumlah elemen:
Compose menawarkan class RoundedCornerShape
dan CutCornerShape
yang dapat Anda gunakan untuk menentukan tema bentuk.
Buat file baru Shape.kt
di paket theme
dan tambahkan hal berikut:
val JetnewsShapes = Shapes(
small = CutCornerShape(topStart = 8.dp),
medium = CutCornerShape(topStart = 24.dp),
large = RoundedCornerShape(8.dp)
)
Buka Theme.kt
dan perbarui composable JetnewsTheme
untuk menggunakan Shapes
berikut:
@Composable
fun JetnewsTheme(content: @Composable () -> Unit) {
MaterialTheme(
colors = LightColors,
typography = JetnewsTypography,
+ shapes = JetnewsShapes,
content = content
)
}
Buka Home.kt
dan muat ulang pratinjau untuk melihat cara Card
yang menampilkan postingan unggulan mencerminkan tema bentuk yang baru diterapkan.
Tema Gelap
Mendukung tema gelap di aplikasi Anda tidak hanya membantu aplikasi terintegrasi lebih baik di perangkat pengguna (yang memiliki tombol tema gelap global mulai dari Android 10 dan seterusnya), tetapi juga dapat mengurangi penggunaan daya dan mendukung kebutuhan aksesibilitas. Material menawarkan panduan desain tentang cara membuat tema gelap. Berikut palet warna alternatif yang ingin kita terapkan untuk tema gelap:
Buka Color.kt
dan tambahkan warna berikut:
val Red200 = Color(0xfff297a2)
val Red300 = Color(0xffea6d7e)
Sekarang buka Theme.kt
dan tambahkan:
private val DarkColors = darkColors(
primary = Red300,
primaryVariant = Red700,
onPrimary = Color.Black,
secondary = Red300,
onSecondary = Color.Black,
error = Red200
)
Sekarang perbarui JetnewsTheme
:
@Composable
fun JetnewsTheme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
MaterialTheme(
+ colors = if (darkTheme) DarkColors else LightColors,
typography = JetnewsTypography,
shapes = JetnewsShapes,
content = content
)
}
Di sini, kita telah menambahkan parameter baru untuk menentukan apakah akan menggunakan tema gelap atau tidak, dan menyetelnya secara default guna mengkueri perangkat untuk setelan global. Hal ini memberi kita default yang baik, tetapi masih mudah untuk diganti jika ingin layar tertentu selalu/tidak pernah gelap atau untuk membuat @Preview
bertema gelap.
Buka Home.kt
dan buat pratinjau baru untuk composable FeaturedPost
yang menampilkannya dalam tema gelap:
@Preview("Featured Post • Dark")
@Composable
private fun FeaturedPostDarkPreview() {
val post = remember { PostRepo.getFeaturedPost() }
JetnewsTheme(darkTheme = true) {
FeaturedPost(post = post)
}
}
Muat ulang panel pratinjau untuk melihat pratinjau tema gelap.
5. Menangani Warna
Di langkah terakhir, kita telah melihat cara membuat tema Anda sendiri untuk menetapkan warna, gaya tulisan, dan bentuk untuk aplikasi Anda. Semua komponen Material menggunakan penyesuaian ini secara langsung. Misalnya, composable FloatingActionButton
secara default menggunakan warna secondary
dari tema, tetapi Anda dapat menetapkan warna alternatif dengan menentukan nilai yang berbeda untuk parameter ini:
@Composable
fun FloatingActionButton(
backgroundColor: Color = MaterialTheme.colors.secondary,
...
) {
Anda tidak selalu ingin menggunakan setelan default, bagian ini menunjukkan cara menggunakan warna di aplikasi Anda.
Warna Mentah
Seperti yang kita lihat sebelumnya, compose menawarkan class Color
. Anda dapat membuat ini secara lokal, menyimpannya di object
, dll:
Surface(color = Color.LightGray) {
Text(
text = "Hard coded colors don't respond to theme changes :(",
textColor = Color(0xffff00ff)
)
}
Color
memiliki sejumlah metode yang berguna, seperti copy
, yang memungkinkan Anda membuat warna baru dengan nilai alfa/merah/hijau/biru yang berbeda.
Warna Tema
Pendekatan yang lebih fleksibel adalah dengan mengambil warna dari tema Anda:
Surface(color = MaterialTheme.colors.primary)
Di sini, kita menggunakan MaterialTheme
object
yang properti colors
-nya menampilkan Colors
yang ditetapkan dalam composable MaterialTheme
. Itu berarti kita dapat mendukung tampilan dan nuansa yang berbeda hanya dengan menyediakan kumpulan warna yang berbeda ke tema kita, dan tidak perlu menyentuh kode aplikasi. Misalnya, AppBar
menggunakan warna primary
dan latar belakang layar adalah surface
; mengubah warna tema akan tercermin dalam composable tersebut:
Karena setiap warna dalam tema kita adalah instance Color
, kita juga dapat dengan mudah memperoleh warna menggunakan metode copy
:
val derivedColor = MaterialTheme.colors.onSurface.copy(alpha = 0.1f)
Di sini, kita membuat salinan warna onSurface
tetapi dengan opasitas 10%. Pendekatan ini memastikan bahwa warna berfungsi di bagian tema yang berbeda, bukan warna statis hard code.
Warna Permukaan & Konten
Banyak komponen menerima sepasang warna dan "warna konten":
Surface(
color: Color = MaterialTheme.colors.surface,
contentColor: Color = contentColorFor(color),
...
TopAppBar(
backgroundColor: Color = MaterialTheme.colors.primarySurface,
contentColor: Color = contentColorFor(backgroundColor),
...
Hal ini memungkinkan Anda untuk tidak hanya menetapkan warna composable, tetapi juga memberikan warna default untuk "konten" yaitu composable di dalamnya. Banyak composable menggunakan warna konten ini secara default, misalnya warna Text
atau tint Icon
. Metode contentColorFor
mengambil warna "aktif" yang sesuai untuk setiap warna tema, mis. jika Anda menetapkan latar belakang primary
, metode ini akan menampilkan onPrimary
sebagai warna konten. Jika Anda menetapkan warna latar belakang non-tema, Anda harus menyediakan warna konten yang masuk akal.
Surface(color = MaterialTheme.colors.primary) {
Text(...) // default text color is 'onPrimary'
}
Surface(color = MaterialTheme.colors.error) {
Icon(...) // default tint is 'onError'
}
Anda dapat menggunakan LocalContentColor
CompositionLocal
untuk mengambil warna yang kontras dengan latar belakang yang sedang digunakan:
BottomNavigationItem(
unselectedContentColor = LocalContentColor.current ...
Saat menetapkan warna elemen apa pun, sebaiknya gunakan Surface
untuk melakukan hal ini karena menetapkan warna konten yang sesuai untuk nilai CompositionLocal
, hati-hati terhadap panggilan Modifier.background
langsung yang tidak menetapkan warna konten yang sesuai.
-Row(Modifier.background(MaterialTheme.colors.primary)) {
+Surface(color = MaterialTheme.colors.primary) {
+ Row(
...
Saat ini, komponen Header
kita selalu memiliki latar belakang Color.LightGray
. Ini terlihat bagus dalam tema terang, tetapi akan memiliki kontras tinggi dengan latar belakang dalam tema gelap. Keduanya juga tidak menentukan warna teks tertentu, jadi warisi warna konten saat ini yang mungkin tidak kontras dengan latar belakangnya:
Mari kita perbaiki. Pada composable Header
di Home.kt
, hapus pengubah background
yang menentukan warna hard code. Sebagai gantinya, gabungkan Text
dalam Surface
dengan warna yang berasal dari tema dan tentukan bahwa konten tersebut harus diberi warna primary
:
+ Surface(
+ color = MaterialTheme.colors.onSurface.copy(alpha = 0.1f),
+ contentColor = MaterialTheme.colors.primary,
+ modifier = modifier
+ ) {
Text(
text = text,
modifier = Modifier
.fillMaxWidth()
- .background(Color.LightGray)
.padding(horizontal = 16.dp, vertical = 8.dp)
)
+ }
Alfa Konten
Sering kali kita ingin menekankan atau tidak menekankan konten untuk menyampaikan nilai penting dan memberikan hierarki visual. Desain Material menyarankan penggunaan berbagai level opasitas untuk menyatakan level nilai penting yang berbeda tersebut.
Jetpack Compose menerapkan ini melalui LocalContentAlpha
. Anda dapat menentukan alfa konten untuk hierarki dengan memberikan nilai untuk CompositionLocal
ini. Komponen turunan dapat menggunakan nilai ini, misalnya Text
dan Icon
secara default menggunakan kombinasi LocalContentColor
yang disesuaikan untuk menggunakan LocalContentAlpha
. Material menentukan beberapa nilai alfa standar ( high
, medium
, disabled
) yang dimodelkan berdasarkan objek ContentAlpha
. Perhatikan bahwa MaterialTheme
menetapkan LocalContentAlpha
secara default ke ContentAlpha.high
.
// By default, both Icon & Text use the combination of LocalContentColor &
// LocalContentAlpha. De-emphasize content by setting a different content alpha
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text(...)
}
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
Icon(...)
Text(...)
}
Hal ini memudahkan dan membuatnya konsisten menyampaikan nilai penting komponen.
Kita akan menggunakan alfa konten untuk memperjelas hierarki informasi dari postingan unggulan. Di Home.kt
, di composable PostMetadata
, buat penekanan medium
metadata:
+ CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text(
text = text,
modifier = modifier
)
+ }
Tema Gelap
Seperti yang telah kita lihat, untuk mengimplementasikan tema gelap di Compose, Anda hanya perlu memberikan kumpulan warna dan warna kueri yang berbeda-beda melalui tema. Beberapa pengecualian catatan adalah:
Anda dapat memeriksa apakah Anda menjalankan tema terang:
val isLightTheme = MaterialTheme.colors.isLight
Nilai ini ditetapkan oleh fungsi builder lightColors/ darkColors.
Pada material, dalam tema gelap, permukaan dengan elevasi yang lebih tinggi menerima overlay elevasi (latar belakangnya akan lebih terang). Hal ini diterapkan secara otomatis saat menggunakan palet warna gelap:
Surface(
elevation = 2.dp,
color = MaterialTheme.colors.surface, // color will be adjusted for elevation
...
Kita dapat melihat perilaku otomatis ini di aplikasi pada komponen TopAppBar
dan Card
yang digunakan; komponen tersebut memiliki elevasi 4dp dan 1dp secara default, sehingga latar belakangnya otomatis akan lebih terang di tema gelap untuk menampilkan elevasi ini dengan lebih baik:
Desain material menyarankan untuk menghindari area luas dengan warna cerah pada tema gelap. Pola yang umum adalah memberi warna primary
pada penampung dalam tema terang dan warna surface
pada tema gelap; banyak komponen menggunakan strategi ini secara default, misalnya Panel Aplikasi dan Navigasi Bawah. Untuk mempermudah implementasi, Colors
menawarkan warna primarySurface
yang memberikan perilaku ini dengan tepat dan komponen ini digunakan secara default.
Aplikasi kita saat ini menetapkan Panel Aplikasi ke warna primary
, kita dapat mengikuti panduan ini dengan mengalihkannya ke primarySurface
atau cukup menghapusnya karena parameter ini adalah default. Di composable AppBar
, ubah parameter backgroundColor
TopAppBar
:
@Composable
private fun AppBar() {
TopAppBar(
...
- backgroundColor = MaterialTheme.colors.primary
+ backgroundColor = MaterialTheme.colors.primarySurface
)
}
6. Menangani Teks
Saat menggunakan teks, kita menggunakan composable Text
untuk menampilkan teks, TextField
dan OutlinedTextField
untuk input teks, dan TextStyle
untuk menerapkan satu gaya pada teks. Kita dapat menggunakan AnnotatedString
untuk menerapkan beberapa gaya ke teks.
Seperti yang kita lihat dengan warna, komponen Material yang menampilkan teks akan mengambil penyesuaian tipografi tema kita:
Button(...) {
Text("This text will use MaterialTheme.typography.button style by default")
}
Mencapai hal ini sedikit lebih rumit daripada menggunakan parameter default seperti yang kita lihat dengan warna. Hal ini karena komponen cenderung tidak menampilkan teks itu sendiri, melainkan menawarkan 'slot API' yang memungkinkan Anda meneruskan composable Text
. Jadi, bagaimana komponen menetapkan gaya tipografi tema? Di balik layar, komponen menggunakan composable ProvideTextStyle
(yang menggunakan CompositionLocal
) untuk menyetel TextStyle
"saat ini". Composable Text
akan disetel secara default untuk melakukan kueri gaya "saat ini" jika Anda tidak memberikan parameter textStyle
konkret.
Misalnya dari class Button
& Text
Compose:
@Composable
fun Button(
// many other parameters
content: @Composable RowScope.() -> Unit
) {
...
ProvideTextStyle(MaterialTheme.typography.button) { //set the "current" text style
...
content()
}
}
@Composable
fun Text(
// many, many parameters
style: TextStyle = LocalTextStyle.current // get the value set by ProvideTextStyle
) { ...
Gaya teks tema
Sama seperti warna, sebaiknya ambil TextStyle
dari tema saat ini, yang mendorong Anda untuk menggunakan kumpulan gaya yang kecil dan konsisten serta membuatnya lebih mudah dikelola. MaterialTheme.typography
mengambil kumpulan instance Typography
di composable MaterialTheme
, sehingga Anda dapat menggunakan gaya yang ditentukan:
Text(
style = MaterialTheme.typography.subtitle2
)
Jika perlu menyesuaikan TextStyle
, Anda dapat melakukan copy
dan mengganti properti (hanya data class
) atau composable Text
menerima sejumlah parameter gaya yang akan ditempatkan di atas TextStyle
:
Text(
text = "Hello World",
style = MaterialTheme.typography.body1.copy(
background = MaterialTheme.colors.secondary
)
)
Text(
text = "Hello World",
style = MaterialTheme.typography.subtitle2,
fontSize = 22.sp // explicit size overrides the size in the style
)
Banyak tempat di aplikasi kita yang otomatis menerapkan tema TextStyle
, misalnya TopAppBar
menata gaya title
-nya karena h6
dan ListItem
menata gaya teks utama dan sekunder masing-masing ke subtitle1
dan body2
.
Mari terapkan gaya tipografi tema ke seluruh aplikasi kita. Setel Header
agar menggunakan subtitle2
dan teks di FeaturedPost
agar menggunakan h6
sebagai judul dan body2
untuk penulis dan metadata:
@Composable
fun Header(...) {
...
Text(
text = text,
+ style = MaterialTheme.typography.subtitle2
Beberapa gaya
Jika perlu menerapkan beberapa gaya ke beberapa teks, Anda dapat menggunakan class AnnotatedString
untuk menerapkan markup, dengan menambahkan SpanStyle
ke berbagai teks. Anda dapat menambahkannya secara dinamis atau menggunakan sintaksis DSL untuk membuat konten:
val text = buildAnnotatedString {
append("This is some unstyled text\n")
withStyle(SpanStyle(color = Color.Red)) {
append("Red text\n")
}
withStyle(SpanStyle(fontSize = 24.sp)) {
append("Large text")
}
}
Mari kita tentukan gaya tag yang menjelaskan setiap postingan di aplikasi. Saat ini, metadata tersebut menggunakan gaya teks yang sama dengan metadata lainnya; kita akan menggunakan gaya teks overline
dan warna latar belakang untuk membedakannya. Dalam composable PostMetadata
:
+ val tagStyle = MaterialTheme.typography.overline.toSpanStyle().copy(
+ background = MaterialTheme.colors.primary.copy(alpha = 0.1f)
+ )
post.tags.forEachIndexed { index, tag ->
...
+ withStyle(tagStyle) {
append(" ${tag.toUpperCase()} ")
+ }
}
7. Menangani Bentuk
Sama seperti warna dan tipografi, penyetelan tema bentuk Anda akan tercermin dalam komponen Material, misalnya Button
akan mengambil kumpulan bentuk untuk komponen kecil:
@Composable
fun Button( ...
shape: Shape = MaterialTheme.shapes.small
) {
Seperti warna, komponen Material menggunakan parameter default sehingga mudah untuk memeriksa kategori bentuk yang akan digunakan oleh komponen, atau untuk memberikan alternatif. Untuk pemetaan lengkap komponen guna membentuk kategori, lihat dokumentasi.
Perhatikan bahwa beberapa komponen menggunakan bentuk tema yang telah dimodifikasi agar sesuai dengan konteksnya. Misalnya, secara default TextField
menggunakan tema bentuk kecil, tetapi menerapkan ukuran sudut nol ke sudut bawah:
@Composable
fun FilledTextField(
// other parameters
shape: Shape = MaterialTheme.shapes.small.copy(
bottomStart = ZeroCornerSize, // overrides small theme style
bottomEnd = ZeroCornerSize // overrides small theme style
)
) {
Bentuk tema
Anda tentu saja dapat menggunakan bentuk saat membuat komponen sendiri dengan menggunakan composable atau Modifier
yang menerima bentuk, misalnya Surface
, Modifier.clip
, Modifier.background
, Modifier.border
, dll.
@Composable
fun UserProfile(
...
shape: Shape = MaterialTheme.shapes.medium
) {
Surface(shape = shape) {
...
}
}
Mari kita tambahkan tema bentuk ke gambar yang ditampilkan di PostItem
; kita akan menerapkan bentuk small
tema ke gambar tersebut dengan clip
Modifier
untuk memotong sudut kiri atas:
@Composable
fun PostItem(...) {
...
Image(
painter = painterResource(post.imageThumbId),
+ modifier = Modifier.clip(shape = MaterialTheme.shapes.small)
)
8. "Gaya" Komponen
Compose tidak menawarkan cara yang eksplisit untuk mengekstrak gaya komponen seperti gaya Android View atau gaya css. Karena semua komponen Compose ditulis di Kotlin, ada cara lain untuk mencapai sasaran yang sama. Sebagai gantinya, buat library komponen kustom sendiri dan gunakan ini di seluruh aplikasi Anda.
Kita sudah melakukan ini di aplikasi:
@Composable
fun Header(
text: String,
modifier: Modifier = Modifier
) {
Surface(
color = MaterialTheme.colors.onSurface.copy(alpha = 0.1f),
contentColor = MaterialTheme.colors.primary,
modifier = modifier.semantics { heading() }
) {
Text(
text = text,
style = MaterialTheme.typography.subtitle2,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp)
)
}
}
Pada dasarnya, composable Header
adalah Text
yang diberi gaya dan dapat kita gunakan di seluruh aplikasi.
Kita telah melihat bahwa semua komponen dibuat dari elemen penyusun yang lebih rendah. Anda dapat menggunakan elemen penyusun yang sama ini untuk menyesuaikan komponen material. Misalnya, kita melihat bahwa Button
menggunakan composable ProvideTextStyle
untuk menetapkan gaya teks default untuk konten yang diteruskan ke sana. Anda dapat menggunakan mekanisme yang sama persis untuk menetapkan gaya teks Anda sendiri:
@Composable
fun LoginButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
content: @Composable RowScope.() -> Unit
) {
Button(
colors = ButtonConstants.defaultButtonColors(
backgroundColor = MaterialTheme.colors.secondary
),
onClick = onClick,
modifier = modifier
) {
ProvideTextStyle(...) { // set our own text style
content()
}
}
}
Dalam contoh ini, kita membuat "gaya" LoginButton
sendiri dengan menggabungkan class Button
standar dan menentukan properti tertentu seperti backgroundColor
dan gaya teks yang berbeda.
Selain itu, tidak ada konsep penataan gaya default, yaitu cara untuk menyesuaikan tampilan default jenis komponen. Sekali lagi, Anda bisa melakukannya dengan membuat komponen sendiri yang menggabungkan dan menyesuaikan komponen library. Misalnya, Anda ingin menyesuaikan bentuk semua Button
di seluruh aplikasi, tetapi tidak ingin mengubah tema bentuk kecil, yang akan memengaruhi komponen (non-Button
) lainnya. Untuk mencapai hal ini, buat komponen Anda sendiri dan gunakan ini pada:
@Composable
fun AcmeButton(
// expose Button params consumers should be able to change
) {
val acmeButtonShape: Shape = ...
Button(
shape = acmeButtonShape,
// other params
)
}
9. Selamat
Selamat, Anda berhasil menyelesaikan codelab ini dan mendesain aplikasi Jetpack Compose.
Anda telah menerapkan tema Material, menyesuaikan warna, tipografi, dan bentuk yang digunakan di seluruh aplikasi untuk mengekspresikan merek Anda dan mendorong konsistensi. Anda telah menambahkan dukungan untuk tema terang dan gelap.
Apa selanjutnya?
Lihat codelab lain di jalur Compose:
Bacaan lebih lanjut
Aplikasi contoh
- Owl mendemonstrasikan beberapa tema
- Jetcaster mendemonstrasikan tema dinamis
- Jetsnack mendemonstrasikan penerapan sistem desain kustom