Jetpack Compose menawarkan implementasi Desain Material, yaitu sistem desain komprehensif untuk membuat antarmuka digital. Komponen Desain Material (tombol, kartu, tombol akses, dan sebagainya) 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. Saat Anda menyesuaikan atribut ini, perubahan Anda akan otomatis tercermin dalam komponen yang Anda gunakan untuk membuat aplikasi.
Jetpack Compose mengimplementasikan konsep ini dengan composable
MaterialTheme:
MaterialTheme( colors = // ... typography = // ... shapes = // ... ) { // app content }
Konfigurasikan parameter yang Anda teruskan ke MaterialTheme untuk tema aplikasi Anda.
Warna
Warna dimodelkan dalam Compose dengan class Color, yaitu class penyimpanan data.
val Red = Color(0xffff0000) val Blue = Color(red = 0f, green = 0f, blue = 1f)
Meskipun Anda dapat mengaturnya sesuka hati (sebagai konstanta tingkat teratas, dalam singleton, atau ditentukan sebagai bagian integral), kami sangat menyarankan untuk menentukan warna dalam tema Anda dan mengambil warna dari sana. Pendekatan ini memungkinkan dukungan untuk tema gelap dan tema bertingkat.
Compose menyediakan class Colors untuk memodelkan sistem warna Material. Colors menyediakan fungsi builder untuk membuat kumpulan warna
terang atau gelap:
private val Yellow200 = Color(0xffffeb46) private val Blue200 = Color(0xff91a4fc) // ... private val DarkColors = darkColors( primary = Yellow200, secondary = Blue200, // ... ) private val LightColors = lightColors( primary = Yellow500, primaryVariant = Yellow400, secondary = Blue700, // ... )
Setelah menentukan Colors, Anda dapat meneruskannya ke MaterialTheme:
MaterialTheme( colors = if (darkTheme) DarkColors else LightColors ) { // app content }
Menggunakan warna tema
Anda dapat mengambil Colors yang disediakan untuk composable MaterialTheme dengan
menggunakan MaterialTheme.colors.
Text( text = "Hello theming", color = MaterialTheme.colors.primary )
Warna permukaan dan konten
Banyak komponen menerima sepasang warna dan warna konten:
Surface( color = MaterialTheme.colors.surface, contentColor = contentColorFor(color), // ... ) { /* ... */ } TopAppBar( backgroundColor = MaterialTheme.colors.primarySurface, contentColor = contentColorFor(backgroundColor), // ... ) { /* ... */ }
Hal ini memungkinkan Anda tidak hanya menetapkan warna composable, tetapi juga memberikan
warna default untuk konten, composable yang ada di dalamnya. Banyak
composable menggunakan warna konten ini secara default. Misalnya, Text mendasarkan warnanya
pada warna konten induknya, dan Icon menggunakan warna tersebut untuk menetapkan warnanya.
Metode contentColorFor() mengambil warna "aktif" yang sesuai untuk
setiap warna tema. Misalnya, jika Anda menyetel warna latar belakang primary pada
Surface, metode tersebut akan menggunakan fungsi ini untuk menyetel onPrimary sebagai warna konten.
Jika menetapkan warna latar belakang non-tema, Anda juga harus menentukan
warna konten yang sesuai. Gunakan LocalContentColor untuk mengambil warna konten pilihan untuk latar belakang saat ini, pada posisi tertentu dalam hierarki.
Alfa konten
Sering kali Anda ingin membedakan seberapa besar Anda menekankan konten untuk menyampaikan pentingnya konten tersebut dan memberikan hierarki visual. Rekomendasi keterbacaan teks Desain Material menyarankan penggunaan berbagai tingkat opasitas untuk menyatakan tingkat kepentingan yang berbeda.
Jetpack Compose menerapkan ini menggunakan LocalContentAlpha. Anda dapat menentukan
alfa konten untuk hierarki dengan memberikan nilai untuk
CompositionLocal ini. Composable bertingkat dapat menggunakan nilai ini untuk menerapkan
perlakuan alfa ke kontennya. 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.
// By default, both Icon & Text use the combination of LocalContentColor & // LocalContentAlpha. De-emphasize content by setting content alpha CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) { Text( // ... ) } CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) { Icon( // ... ) Text( // ... ) }
Untuk mempelajari CompositionLocal lebih lanjut, lihat Data yang tercakup secara lokal dengan
CompositionLocal.
ContentAlpha.high. Baris kedua berisi metadata yang kurang penting, sehingga menggunakan ContentAlpha.medium.Tema gelap
Di Compose, Anda menerapkan tema terang dan gelap dengan menyediakan berbagai kumpulan
Colors ke composable MaterialTheme:
@Composable fun MyTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { MaterialTheme( colors = if (darkTheme) DarkColors else LightColors, /*...*/ content = content ) }
Dalam contoh ini, MaterialTheme dikemas dalam fungsi composable-nya sendiri,
yang menerima parameter yang menentukan apakah akan menggunakan tema gelap atau tidak. Dalam
hal ini, fungsi tersebut akan mendapatkan nilai default untuk darkTheme dengan membuat kueri
setelan tema perangkat.
Anda dapat menggunakan kode seperti ini untuk memeriksa apakah Colors saat ini sedang terang atau gelap:
val isLightTheme = MaterialTheme.colors.isLight Icon( painterResource( id = if (isLightTheme) { R.drawable.ic_sun_24 } else { R.drawable.ic_moon_24 } ), contentDescription = "Theme" )
Overlay ketinggian
Pada Material, permukaan tema gelap dengan elevasi yang lebih tinggi menerima overlay elevasi, yang akan mencerahkan latar belakangnya. Semakin tinggi elevasi permukaan (yang mengangkatnya lebih dekat ke sumber cahaya tersirat), semakin terang permukaan tersebut.
Composable Surface menerapkan overlay ini secara otomatis saat menggunakan
warna gelap, begitu juga dengan composable Material lainnya yang menggunakan permukaan:
Surface( elevation = 2.dp, color = MaterialTheme.colors.surface, // color will be adjusted for elevation /*...*/ ) { /*...*/ }
surface sebagai latar belakangnya. Karena kartu dan navigasi bawah berada pada level elevasi yang berbeda di atas latar belakang, warnanya sedikit berbeda. Kartu lebih terang dari latar belakang dan navigasi bawah lebih terang daripada kartu.Untuk skenario kustom yang tidak melibatkan Surface, gunakan
LocalElevationOverlay, CompositionLocal yang berisi
ElevationOverlay yang digunakan oleh komponen Surface:
// Elevation overlays // Implemented in Surface (and any components that use it) val color = MaterialTheme.colors.surface val elevation = 4.dp val overlaidColor = LocalElevationOverlay.current?.apply( color, elevation )
Untuk menonaktifkan overlay ketinggian, berikan null di titik yang dipilih dalam
hierarki composable:
MyTheme { CompositionLocalProvider(LocalElevationOverlay provides null) { // Content without elevation overlays } }
Aksen warna terbatas
Material merekomendasikan penerapan aksen warna terbatas untuk tema
gelap dengan lebih memilih penggunaan warna surface daripada warna primary pada
sebagian besar kasus. Composable Material seperti TopAppBar dan BottomNavigation
menerapkan perilaku ini secara default.
Untuk skenario kustom, gunakan properti ekstensi primarySurface:
Surface( // Switches between primary in light theme and surface in dark theme color = MaterialTheme.colors.primarySurface, /*...*/ ) { /*...*/ }
Tipografi
Material menentukan sistem huruf, yang mendorong Anda untuk menggunakan sejumlah kecil gaya dengan nama semantik.
Compose menerapkan sistem huruf dengan class Typography,
TextStyle, dan terkait font. Konstruktor Typography
menawarkan default untuk setiap gaya sehingga Anda dapat menghilangkan gaya yang tidak ingin Anda sesuaikan:
val raleway = FontFamily( Font(R.font.raleway_regular), Font(R.font.raleway_medium, FontWeight.W500), Font(R.font.raleway_semibold, FontWeight.SemiBold) ) val myTypography = Typography( h1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W300, fontSize = 96.sp ), body1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W600, fontSize = 16.sp ) /*...*/ ) MaterialTheme(typography = myTypography, /*...*/) { /*...*/ }
Jika Anda ingin menggunakan jenis huruf yang sama secara keseluruhan, tentukan parameter
defaultFontFamily dan hapus fontFamily dari setiap elemen
TextStyle:
val typography = Typography(defaultFontFamily = raleway) MaterialTheme(typography = typography, /*...*/) { /*...*/ }
Menggunakan gaya teks
Elemen TextStyle diakses menggunakan MaterialTheme.typography. Ambil
elemen TextStyle sebagai berikut:
Text( text = "Subtitle2 styled", style = MaterialTheme.typography.subtitle2 )
Bentuk
Material menentukan sistem bentuk, yang memungkinkan Anda menentukan bentuk untuk komponen besar, sedang, dan kecil.
Compose menerapkan sistem bentuk dengan class Shapes, yang memungkinkan
Anda menentukan CornerBasedShape untuk setiap kategori ukuran:
val shapes = Shapes( small = RoundedCornerShape(percent = 50), medium = RoundedCornerShape(0f), large = CutCornerShape( topStart = 16.dp, topEnd = 0.dp, bottomEnd = 0.dp, bottomStart = 16.dp ) ) MaterialTheme(shapes = shapes, /*...*/) { /*...*/ }
Banyak komponen menggunakan bentuk ini secara default. Misalnya, Button,
TextField, dan FloatingActionButton secara default ditetapkan ke kecil,
AlertDialog secara default ditetapkan ke sedang, dan ModalDrawer secara default ditetapkan ke
besar — lihat referensi skema bentuk untuk pemetaan
lengkap.
Menggunakan bentuk
Elemen Shape diakses menggunakan MaterialTheme.shapes. Ambil elemen
Shape dengan kode seperti ini:
Surface( shape = MaterialTheme.shapes.medium, /*...*/ ) { /*...*/ }
Gaya default
Tidak ada konsep yang setara di Compose dengan gaya default dari Android
View. Anda dapat menyediakan fungsi serupa dengan membuat fungsi composable overload
Anda sendiri yang menggabungkan komponen Material. Misalnya, untuk membuat
gaya tombol, letakkan tombol dalam fungsi composable Anda sendiri, sehingga langsung menetapkan
parameter yang ingin atau perlu Anda ubah dan menampilkan yang lain sebagai parameter ke
composable yang memuatnya.
@Composable fun MyButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary ), onClick = onClick, modifier = modifier, content = content ) }
Overlay tema
Anda dapat mencapai overlay tema yang setara dari Tampilan Android di Compose dengan menyarangkan komponen MaterialTheme. Karena
MaterialTheme menetapkan warna, tipografi, dan bentuk ke nilai tema saat ini secara default, semua parameter lainnya akan mempertahankan nilai defaultnya jika tema hanya menetapkan salah satu parameter tersebut.
Selain itu, saat memigrasikan layar berbasis View ke Compose, perhatikan penggunaan
atribut android:theme. Sepertinya Anda memerlukan MaterialTheme baru di bagian pohon UI Compose.
Dalam contoh ini, layar detail menggunakan PinkTheme untuk sebagian besar layar,
lalu BlueTheme untuk bagian terkait. Screenshot dan kode berikut mengilustrasikan konsep ini:
@Composable fun DetailsScreen(/* ... */) { PinkTheme { // other content RelatedSection() } } @Composable fun RelatedSection(/* ... */) { BlueTheme { // content } }
Status komponen
Komponen material yang dapat berinteraksi (diklik, dialihkan, dsb.) dapat berada dalam status visual yang berbeda. Status mencakup diaktifkan, dinonaktifkan, ditekan, dll.
Composable sering memiliki parameter enabled. Menyetelnya ke false akan mencegah
interaksi, dan mengubah properti seperti warna dan ketinggian untuk menyampaikan
status komponen secara visual.
enabled = true (kiri) dan enabled = false (kanan).Pada umumnya, Anda dapat menggunakan nilai default untuk nilai seperti warna dan ketinggian. Jika Anda perlu mengonfigurasi nilai yang digunakan dalam status berbeda, tersedia class dan fungsi praktis. Perhatikan contoh tombol berikut:
Button( onClick = { /* ... */ }, enabled = true, // Custom colors for different states colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary, disabledBackgroundColor = MaterialTheme.colors.onBackground .copy(alpha = 0.2f) .compositeOver(MaterialTheme.colors.background) // Also contentColor and disabledContentColor ), // Custom elevation for different states elevation = ButtonDefaults.elevation( defaultElevation = 8.dp, disabledElevation = 2.dp, // Also pressedElevation ) ) { /* ... */ }
enabled = true (kiri) dan enabled = false (kanan), dengan nilai warna dan ketinggian yang disesuaikan.Ripple
Komponen Material menggunakan ripple untuk menunjukkan bahwa mereka sedang berinteraksi. Jika
Anda menggunakan MaterialTheme dalam hierarki, jenis Ripple akan digunakan sebagai
default Indication di dalam pengubah seperti clickable dan
indication.
Dalam sebagian besar kasus, Anda dapat menggunakan Ripple default. Jika perlu
mengonfigurasi tampilannya, Anda dapat menggunakan RippleTheme untuk mengubah properti
seperti warna dan alfa.
Anda dapat memperluas RippleTheme dan memanfaatkan fungsi utilitas defaultRippleColor dan
defaultRippleAlpha. Kemudian, Anda dapat memberikan tema ripple kustom dalam hierarki menggunakan LocalRippleTheme:
@Composable fun MyApp() { MaterialTheme { CompositionLocalProvider( LocalRippleTheme provides SecondaryRippleTheme ) { // App content } } } @Immutable private object SecondaryRippleTheme : RippleTheme { @Composable override fun defaultColor() = RippleTheme.defaultRippleColor( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) @Composable override fun rippleAlpha() = RippleTheme.defaultRippleAlpha( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) }
RippleTheme.Pelajari lebih lanjut
Untuk mempelajari Tema Material dalam Compose lebih lanjut, lihat referensi tambahan berikut.
Codelab
Video
Direkomendasikan untuk Anda
- Catatan: teks link ditampilkan saat JavaScript nonaktif
- Sistem desain kustom di Compose
- Bermigrasi dari Material 2 ke Material 3 di Compose
- Aksesibilitas di Compose