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 otomatis tercermin dalam komponen yang digunakan 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.
Gambar 1. Screenshot pertama menunjukkan aplikasi yang tidak mengonfigurasi
MaterialTheme
, sehingga akan menggunakan gaya default. Screenshot kedua menampilkan
aplikasi yang meneruskan parameter ke MaterialTheme
untuk menyesuaikan gaya.
Warna
Warna dimodelkan dalam Compose dengan class Color
, yaitu sebuah class
penyimpanan data sederhana.
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.
Gambar 2. Sistem warna Material.
Compose menyediakan class Colors
untuk membuat model
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 untuk 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.
Gambar 3. Menetapkan warna latar belakang yang berbeda akan menghasilkan warna teks dan ikon yang berbeda.
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 kepentingan yang berbeda.
Jetpack Compose menerapkan ini melalui LocalContentAlpha
.
Anda dapat menentukan alfa konten untuk hierarki denganmemberikan
nilai untuk CompositionLocal
.
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 dicakup secara lokal dengan
panduan CompositionLocal.
Gambar 4. Terapkan berbagai tingkat penekanan pada teks untuk menyampaikan
hierarki informasi secara visual. Baris pertama teks adalah judul dan berisi
informasi paling penting, sehingga menggunakan 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 ketinggian permukaan (yang mengangkatnya lebih dekat ke sumber cahaya tersirat), semakin terang permukaan tersebut.
Overlay ini diterapkan secara otomatis oleh composable Surface
saat menggunakan
warna gelap, dan untuk composable Material lainnya yang menggunakan permukaan:
Surface( elevation = 2.dp, color = MaterialTheme.colors.surface, // color will be adjusted for elevation /*...*/ ) { /*...*/ }
Gambar 5. Kartu dan navigasi bawah menggunakan warna 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
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 diinginkan 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.
Gambar 6. Tema gelap Material dengan aksen warna terbatas. Panel aplikasi atas menggunakan warna utama dalam tema terang, dan warna permukaan dalam tema gelap.
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 jenis, yang mendorong Anda untuk menggunakan sejumlah kecil gaya dengan nama semantik.
Gambar 7. Sistem jenis Material.
Compose menerapkan sistem jenis 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
defaultFontFamily parameter
dan hapus TextStyle
apa pun dari fontFamily
:
val typography = Typography(defaultFontFamily = raleway) MaterialTheme(typography = typography, /*...*/) { /*...*/ }
Menggunakan gaya teks
TextStyle
diakses melalui MaterialTheme.typography
. Ambil
TextStyle
seperti ini:
Text( text = "Subtitle2 styled", style = MaterialTheme.typography.subtitle2 )
Gambar 8. Gunakan pilihan jenis huruf dan gaya untuk mengekspresikan merek Anda.
Bentuk
Material menetapkan sistem bentuk, yang memungkinkan Anda menentukan bentuk untuk komponen besar, sedang, dan kecil.
Gambar 9. Sistem bentuk Material.
Compose menerapkan sistem bentuk dengan
class Shapes
, yang memungkinkan
Anda menentukan
CornerBasedShape
untuk masing-masing 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 ukuran kecil,
AlertDialog
ditetapkan ke sedang, dan
ModalDrawer
ditetapkan ke besar - lihat
referensi skema bentuk
untuk pemetaan lengkap.
Menggunakan bentuk
Shape
diakses melalui MaterialTheme.shapes
. Ambil Shape
dengan
kode seperti ini:
Surface( shape = MaterialTheme.shapes.medium, /*...*/ ) { /*...*/ }
Gambar 10. Gunakan bentuk untuk mengekspresikan merek atau status.
Gaya default
Tidak ada konsep yang setara di Compose dengan gaya default dari Tampilan Android. 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 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, jika tema hanya menetapkan salah satu parameter tersebut, parameter lainnya akan mempertahankan nilai defaultnya.
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. Lihat screenshot dan kode di bawah.
Gambar 11. Tema bertingkat.
@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.
Gambar 12. Tombol dengan enabled = true
(kiri) dan enabled = false
(kanan).
Pada umumnya, Anda dapat menggunakan nilai default untuk nilai seperti warna dan ketinggian. Jika Anda ingin mengonfigurasi nilai yang digunakan dalam status berbeda, tersedia class dan fungsi praktis. Lihat contoh tombol di bawah ini:
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 ) ) { /* ... */ }
Gambar 13. Tombol dengan 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 menggunakanMaterialTheme
dalam hierarki, jenis Ripple
akan digunakan sebagai
defaultIndication
di dalam pengubah seperti
clickable
dan
indication
data.
Dalam sebagian besar kasus, Anda dapat menggunakan Ripple
default. Jika ingin 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 ) }
Gambar 14. Tombol dengan nilai ripple berbeda yang disediakan melalui RippleTheme
.
Mempelajari 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