1. Pengantar
Sebagai toolkit UI, Compose memudahkan Anda menerapkan desain aplikasi. Anda mendeskripsikan tampilan UI yang Anda inginkan, dan Compose akan menggambarnya di layar. Codelab ini mengajarkan cara menulis UI Compose. Hal ini mengasumsikan bahwa Anda memahami konsep yang diajarkan di codelab dasar-dasar, jadi pastikan Anda menyelesaikan codelab tersebut terlebih dahulu. Di codelab Dasar, Anda telah mempelajari cara mengimplementasikan tata letak sederhana menggunakan Surfaces
, Rows
, dan Columns
. Anda juga meningkatkan tata letak ini dengan pengubah seperti padding
, fillMaxWidth
, dan size
.
Dalam codelab ini, Anda akan menerapkan tata letak yang lebih realistis dan kompleks untuk mempelajari berbagai composable siap pakai dan pengubah di sepanjang proses. Setelah menyelesaikan codelab ini, Anda seharusnya dapat mengubah desain aplikasi dasar menjadi kode yang berfungsi.
Codelab ini tidak menambahkan perilaku aktual ke aplikasi. Sebagai gantinya, untuk mempelajari status dan interaksi, selesaikan codelab Status dalam Compose.
Untuk mendapatkan dukungan lebih lanjut saat Anda mempelajari codelab ini, lihat kode berikut:
Yang akan Anda pelajari
Dalam codelab ini, Anda akan mempelajari:
- Cara pengubah membantu Anda meningkatkan composable.
- Cara komponen tata letak standar seperti Column dan LazyRow memosisikan composable turunan.
- Cara perataan dan pengaturan mengubah posisi composable turunan di induknya.
- Cara composable Material seperti Scaffold dan Navigasi Bawah membantu Anda membuat tata letak komprehensif.
- Cara membangun composable fleksibel menggunakan API slot.
- Cara membangun tata letak untuk berbagai konfigurasi layar.
Yang akan Anda butuhkan
- Android Studio Terbaru.
- Pengalaman dengan sintaksis Kotlin, termasuk lambda.
- Pengalaman dasar dengan Compose. Jika Anda belum melakukannya, selesaikan codelab Dasar-dasar Jetpack Compose sebelum memulai codelab ini.
- Pengetahuan dasar tentang pengertian composable dan pengubahnya.
Yang akan Anda build
Dalam codelab ini, Anda akan menerapkan desain aplikasi yang realistis berdasarkan tiruan yang disediakan oleh desainer. MySoothe adalah aplikasi kesehatan yang mencatat berbagai cara untuk meningkatkan kesehatan tubuh dan pikiran. Aplikasi ini berisi bagian yang mencantumkan koleksi favorit Anda dan bagian dengan latihan fisik. Tampilan aplikasi akan terlihat seperti berikut:
2. Mempersiapkan
Pada langkah ini, Anda akan mendownload kode yang berisi tema dan beberapa penyiapan dasar.
Mendapatkan kode
Kode untuk codelab ini dapat ditemukan di repositori GitHub codelab-android-compose. Untuk melakukan clone kode ini, jalankan:
$ git clone https://github.com/android/codelab-android-compose
Atau, Anda dapat mendownload dua file ZIP:
Melihat kode
Kode yang didownload berisi kode untuk semua codelab Compose yang tersedia. Untuk menyelesaikan codelab ini, buka project BasicLayoutsCodelab
di dalam Android Studio.
Sebaiknya Anda memulai dengan kode di cabang main
dan mengikuti codelab langkah demi langkah sesuai kemampuan Anda.
3. Mulai dengan rencana
Kita akan mulai dengan menerapkan desain potret aplikasi - mari kita pelajari lebih lanjut:
Saat Anda diminta menerapkan desain, cara yang baik untuk memulai adalah dengan memahami strukturnya dengan jelas. Jangan langsung memulai coding, tetapi analisis desainnya. Bagaimana cara membagi UI ini menjadi beberapa bagian yang dapat digunakan kembali?
Jadi, mari kita coba desain kami. Pada level abstraksi tertinggi, kita dapat membagi desain ini menjadi dua bagian:
- Konten layar.
- Navigasi bawah.
Melihat perincian, konten layar berisi tiga sub-bagian:
- Kotak penelusuran.
- Bagian bernama "Align your body".
- Bagian yang disebut "Favorite collections".
Di dalam setiap bagian, Anda juga dapat melihat beberapa komponen dengan level lebih rendah yang digunakan kembali:
- Elemen "align your body" yang ditampilkan dalam baris yang dapat di-scroll secara horizontal.
- Kartu "favorite collection" (koleksi favorit) yang ditampilkan dalam petak yang dapat di-scroll secara horizontal.
Setelah menganalisis desain, Anda dapat mulai menerapkan composable untuk setiap bagian UI yang diidentifikasi. Mulai dengan composable level terendah dan terus gabungkan ke dalam composable yang lebih kompleks. Di akhir codelab, aplikasi baru Anda akan terlihat seperti desain yang disediakan.
4. Kotak penelusuran - Pengubah
Elemen pertama yang berubah menjadi composable adalah Kotak penelusuran. Mari perhatikan kembali desainnya:
Berdasarkan screenshot ini saja, akan sangat sulit untuk menerapkan desain ini dengan cara yang sempurna untuk piksel. Umumnya, seorang desainer menyampaikan lebih banyak informasi tentang desainnya. Mereka dapat memberi Anda akses ke alat desain mereka, atau membagikan apa yang disebut desain redlining. Dalam hal ini, desainer kami menyerahkan desain redlining, yang dapat Anda gunakan untuk membaca semua nilai ukuran. Desain ditampilkan dengan overlay petak 8 dp, sehingga Anda dapat dengan mudah melihat seberapa banyak ruang antara dan di sekitar elemen. Selain itu, beberapa spasi ditambahkan secara eksplisit untuk memperjelas ukuran tertentu.
Anda dapat melihat bahwa kotak penelusuran harus memiliki tinggi 56 piksel kepadatan mandiri. Class ini juga harus mengisi lebar penuh induknya.
Untuk menerapkan kotak penelusuran, gunakan komponen Material yang disebut Kolom teks. Library Compose Material berisi composable yang disebut TextField
, yang merupakan implementasi komponen Material ini.
Mulai dengan implementasi TextField
dasar. Di code base, buka MainActivity.kt
dan telusuri composable SearchBar
.
Di dalam composable yang disebut SearchBar
, tulis implementasi TextField
dasar:
import androidx.compose.material3.TextField
@Composable
fun SearchBar(
modifier: Modifier = Modifier
) {
TextField(
value = "",
onValueChange = {},
modifier = modifier
)
}
Beberapa hal yang perlu diperhatikan:
- Anda melakukan hardcode pada nilai kolom teks, dan callback
onValueChange
tidak melakukan apa pun. Karena ini adalah codelab yang berfokus pada tata letak, Anda mengabaikan apa pun yang berkaitan dengan status.
- Fungsi composable
SearchBar
menerima parametermodifier
dan meneruskannya keTextField
. Ini merupakan praktik terbaik sesuai pedoman Compose. Hal ini memungkinkan pemanggil metode untuk mengubah tampilan & nuansa composable, yang membuatnya lebih fleksibel dan dapat digunakan kembali. Anda akan melanjutkan praktik terbaik ini untuk semua composable di codelab ini.
Mari kita lihat pratinjau composable ini. Ingat bahwa Anda dapat menggunakan fungsi Pratinjau di Android Studio untuk melakukan iterasi dengan cepat pada setiap composable. MainActivity.kt
berisi pratinjau untuk semua composable yang akan Anda build dalam codelab ini. Dalam hal ini, metode SearchBarPreview
merender composable SearchBar
, dengan beberapa latar belakang dan padding untuk memberikan sedikit lebih banyak konteks. Dengan implementasi yang baru saja Anda tambahkan, tampilannya akan terlihat seperti ini:
Ada beberapa hal yang hilang. Pertama, mari perbaiki ukuran composable menggunakan pengubah.
Saat menulis composable, Anda menggunakan pengubah untuk:
- Mengubah ukuran, tata letak, perilaku, dan tampilan composable.
- Menambahkan informasi, seperti label aksesibilitas.
- Memproses input pengguna.
- Menambahkan interaksi tingkat tinggi, seperti membuat elemen yang dapat diklik, dapat di-scroll, dapat ditarik, atau dapat di-zoom.
Setiap composable yang Anda panggil memiliki parameter modifier
yang dapat ditetapkan untuk menyesuaikan tampilan, nuansa, dan perilaku composable tersebut. Saat menetapkan pengubah, Anda dapat merangkai beberapa metode pengubah untuk membuat adaptasi yang lebih kompleks.
Dalam hal ini, kotak penelusuran harus berukuran minimal 56 dp, dan mengisi lebar induknya. Untuk menemukan pengubah yang tepat, Anda dapat melihat daftar pengubah dan melihat bagian Ukuran. Untuk tinggi, Anda dapat menggunakan pengubah heightIn
. Ini memastikan bahwa composable memiliki tinggi minimum tertentu. Namun, ukuran halaman dapat menjadi lebih besar misalnya, jika pengguna memperbesar ukuran font sistem. Untuk lebar, Anda dapat menggunakan pengubah fillMaxWidth
. Pengubah ini memastikan bahwa kotak penelusuran menggunakan semua ruang horizontal dari induknya.
Update pengubah agar cocok dengan kode di bawah ini:
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.material3.TextField
@Composable
fun SearchBar(
modifier: Modifier = Modifier
) {
TextField(
value = "",
onValueChange = {},
modifier = modifier
.fillMaxWidth()
.heightIn(min = 56.dp)
)
}
Dalam hal ini, karena satu pengubah memengaruhi lebar, dan yang lainnya memengaruhi tinggi, urutan pengubah ini tidak berpengaruh.
Anda juga harus menetapkan beberapa parameter TextField
. Cobalah untuk membuat composable terlihat seperti desain dengan menetapkan nilai parameter. Berikut desainnya lagi sebagai referensi:
Berikut adalah langkah-langkah yang sebaiknya Anda lakukan untuk mengupdate implementasi:
- Tambahkan ikon penelusuran.
TextField
berisi parameterleadingIcon
yang menerima composable lain. Di dalam, Anda dapat menetapkanIcon
, yang dalam hal ini berupa ikonSearch
. Pastikan untuk menggunakan imporIcon
Compose yang tepat. - Anda dapat menggunakan
TextFieldDefaults.textFieldColors
untuk mengganti warna tertentu. SetelfocusedContainerColor
danunfocusedContainerColor
kolom teks ke warnasurface
MaterialTheme. - Tambahkan teks placeholder "Search" (Anda dapat menemukannya sebagai resource string
R.string.placeholder_search
).
Setelah selesai, composable Anda akan terlihat seperti ini:
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.ui.res.stringResource
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
@Composable
fun SearchBar(
modifier: Modifier = Modifier
) {
TextField(
value = "",
onValueChange = {},
leadingIcon = {
Icon(
imageVector = Icons.Default.Search,
contentDescription = null
)
},
colors = TextFieldDefaults.colors(
unfocusedContainerColor = MaterialTheme.colorScheme.surface,
focusedContainerColor = MaterialTheme.colorScheme.surface
),
placeholder = {
Text(stringResource(R.string.placeholder_search))
},
modifier = modifier
.fillMaxWidth()
.heightIn(min = 56.dp)
)
}
Perhatikan bahwa:
- Anda menambahkan
leadingIcon
yang menampilkan ikon penelusuran. Ikon ini tidak memerlukan deskripsi konten, karena placeholder kolom teks telah menjelaskan arti kolom teks. Ingat bahwa deskripsi konten biasanya digunakan untuk tujuan aksesibilitas dan memberikan representasi tekstual dari gambar atau ikon aplikasi kepada pengguna.
- Untuk menyesuaikan warna latar belakang kolom teks, Anda harus menyetel properti
colors
. Sebagai ganti parameter terpisah untuk setiap warna, composable dapat berisi satu parameter gabungan. Di sini, Anda meneruskan salinan class dataTextFieldDefaults
, tempat Anda hanya mengubah warna yang berbeda. Dalam hal ini, itu hanya warnaunfocusedContainerColor
danfocusedContainerColor
.
Pada langkah ini, Anda telah melihat cara menggunakan parameter dan pengubah composable untuk mengubah tampilan dan nuansa composable. Ini berlaku untuk composable yang disediakan oleh library Compose dan Material, serta yang Anda tulis sendiri. Anda harus selalu memikirkan penyediaan parameter untuk menyesuaikan composable yang ditulis. Anda juga harus menambahkan properti modifier
sehingga tampilan dan nuansa composable dapat disesuaikan dari luar.
5. Align your body - Perataan
Composable berikutnya yang akan Anda terapkan adalah elemen "Selaraskan tubuh Anda". Mari kita lihat desainnya, termasuk desain garis merah di sampingnya:
Desain garis merah kini juga berisi spasi berorientasi dasar pengukuran. Berikut adalah informasi yang kami peroleh dari laporan tersebut:
- Gambar harus berukuran 88 dp.
- Spasi antara dasar pengukuran teks dan gambar harus 24dp.
- Jarak antara dasar pengukuran dan bagian bawah elemen harus 8 dp.
- Teks harus bergaya tipografi bodyMedium.
Untuk menerapkan composable ini, Anda memerlukan composable Image
dan Text
. Keduanya perlu disertakan dalam Column
, sehingga diposisikan di bawah satu sama lain.
Temukan composable AlignYourBodyElement
dalam kode Anda dan update kontennya dengan implementasi dasar ini:
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.ui.res.painterResource
@Composable
fun AlignYourBodyElement(
modifier: Modifier = Modifier
) {
Column(
modifier = modifier
) {
Image(
painter = painterResource(R.drawable.ab1_inversions),
contentDescription = null
)
Text(text = stringResource(R.string.ab1_inversions))
}
}
Perhatikan bahwa:
- Anda menyetel
contentDescription
gambar ke null, karena gambar ini hanya bersifat dekoratif. Teks di bawah gambar menjelaskan maknanya secara memadai, sehingga gambar tidak memerlukan deskripsi tambahan. - Anda menggunakan gambar dan teks hard code. Pada langkah berikutnya, Anda akan memindahkan gambar dan teks hard code ini untuk dapat menggunakan parameter yang disediakan di composable
AlignYourBodyElement
agar keduanya dinamis.
Lihat pratinjau composable ini:
Ada beberapa peningkatan yang harus dilakukan. Yang paling kentara, gambar terlalu besar dan tidak berbentuk lingkaran. Anda dapat menyesuaikan composable Image
dengan pengubah size
dan clip
serta parameter contentScale
.
Pengubah size
menyesuaikan composable agar sesuai dengan ukuran tertentu, mirip dengan pengubah fillMaxWidth
dan heightIn
yang Anda lihat di langkah sebelumnya. Pengubah clip
berfungsi secara berbeda dan mengadaptasi tampilan composable. Anda dapat menetapkannya ke Shape
mana pun dan konten klip tersebut akan disusun ke bentuk tersebut.
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.draw.clip
@Composable
fun AlignYourBodyElement(
modifier: Modifier = Modifier
) {
Column(
modifier = modifier
) {
Image(
painter = painterResource(R.drawable.ab1_inversions),
contentDescription = null,
modifier = Modifier
.size(88.dp)
.clip(CircleShape)
)
Text(text = stringResource(R.string.ab1_inversions))
}
}
Saat ini, desain Anda di Pratinjau terlihat seperti ini:
Gambar juga harus diskalakan dengan benar. Untuk melakukannya, kita dapat menggunakan parameter contentScale
Image
. Ada beberapa opsi, terutama:
Dalam hal ini, jenis pemangkasan adalah yang benar untuk digunakan. Setelah menerapkan pengubah dan parameter, kode Anda akan terlihat seperti ini:
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
@Composable
fun AlignYourBodyElement(
modifier: Modifier = Modifier
) {
Column(
modifier = modifier
) {
Image(
painter = painterResource(R.drawable.ab1_inversions),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.size(88.dp)
.clip(CircleShape)
)
Text( text = stringResource(R.string.ab1_inversions) )
}
}
Desain Anda sekarang akan terlihat seperti ini:
Sebagai langkah berikutnya, ratakan teks secara horizontal dengan menyetel perataan Column
.
Secara umum, untuk meratakan composable di dalam penampung induk, Anda harus menyetel perataan penampung induk tersebut. Jadi, bukannya memberi tahu anak agar memosisikan dirinya sendiri di induknya, Anda memberi tahu induk cara menyelaraskan turunan.
Untuk Column
, tentukan bagaimana turunan harus diratakan secara horizontal. Opsinya adalah:
- Mulai
- CenterHorizontally
- Akhir
Untuk Row
, Anda menyetel perataan vertikal. Opsinya mirip dengan Column
:
- Atas
- CenterVertically
- Bawah
Untuk Box
, Anda menggabungkan perataan horizontal dan vertikal. Opsinya adalah:
- TopStart
- TopCenter
- TopEnd
- CenterStart
- Center
- CenterEnd
- BottomStart
- BottomCenter
- BottomEnd
Semua turunan penampung akan mengikuti pola penyelarasan yang sama ini. Anda dapat mengganti perilaku turunan tunggal dengan menambahkan pengubah align
ke dalamnya.
Untuk desain ini, teks harus berada di tengah secara horizontal. Untuk melakukannya, setel horizontalAlignment
Column
ke tengah secara horizontal:
import androidx.compose.ui.Alignment
@Composable
fun AlignYourBodyElement(
modifier: Modifier = Modifier
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
) {
Image(
//..
)
Text(
//..
)
}
}
Dengan menerapkan bagian-bagian ini, maka hanya ada beberapa perubahan kecil yang perlu Anda lakukan untuk membuat composable identik dengan desainnya. Coba terapkan kode ini sendiri atau lihat kode akhir jika Anda mengalami kesulitan. Pertimbangkan langkah berikut:
- Jadikan gambar dan teks dinamis. Teruskan argumen tersebut sebagai argumen ke fungsi composable. Jangan lupa untuk mengupdate Pratinjau yang sesuai dan meneruskan beberapa data hard code.
- Perbarui teks agar menggunakan gaya tipografi bodyMedium.
- Perbarui spasi dasar elemen teks per diagram.
Setelah selesai menerapkan langkah-langkah ini, kode Anda akan terlihat seperti ini:
import androidx.compose.foundation.layout.paddingFromBaseline
import androidx.compose.ui.Alignment
import androidx.compose.ui.layout.ContentScale
@Composable
fun AlignYourBodyElement(
@DrawableRes drawable: Int,
@StringRes text: Int,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(drawable),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.size(88.dp)
.clip(CircleShape)
)
Text(
text = stringResource(text),
modifier = Modifier.paddingFromBaseline(top = 24.dp, bottom = 8.dp),
style = MaterialTheme.typography.bodyMedium
)
}
}
@Preview(showBackground = true, backgroundColor = 0xFFF5F0EE)
@Composable
fun AlignYourBodyElementPreview() {
MySootheTheme {
AlignYourBodyElement(
text = R.string.ab1_inversions,
drawable = R.drawable.ab1_inversions,
modifier = Modifier.padding(8.dp)
)
}
}
Lihat AlignYourBodyElement di tab Design.
6. Kartu Favorite collection - Platform Material
Composable berikutnya yang akan diimplementasikan sama dengan elemen "Align the body". Berikut adalah desainnya, termasuk garis merah:
Dalam hal ini, ukuran penuh composable disediakan. Anda dapat melihat bahwa teks harus titleMedium.
Penampung ini menggunakan surfaceVariant sebagai warna latar belakangnya yang berbeda dari latar belakang seluruh layar. Ada juga sudut yang membulat. Kita menentukan ini untuk kartu koleksi favorit menggunakan composable Surface
Material.
Anda dapat menyesuaikan Surface
sesuai kebutuhan dengan menetapkan parameter dan pengubahnya. Dalam hal ini, permukaan harus memiliki sudut bulat. Anda dapat menggunakan parameter shape
untuk ini. Anda akan menggunakan nilai yang berasal dari tema Material, bukan menyetel bentuk ke Shape
seperti Gambar di langkah sebelumnya.
Mari kita lihat tampilannya:
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.Surface
@Composable
fun FavoriteCollectionCard(
modifier: Modifier = Modifier
) {
Surface(
shape = MaterialTheme.shapes.medium,
modifier = modifier
) {
Row {
Image(
painter = painterResource(R.drawable.fc2_nature_meditations),
contentDescription = null
)
Text(text = stringResource(R.string.fc2_nature_meditations))
}
}
}
Mari kita lihat Pratinjau implementasi ini:
Selanjutnya, terapkan hal yang dipelajari pada langkah sebelumnya.
- Tetapkan lebar
Row
, dan sejajarkan turunannya secara vertikal. - Menetapkan ukuran gambar per diagram dan memangkasnya dalam penampungnya.
Coba terapkan perubahan ini sendiri sebelum melihat kode solusi.
Kode Anda sekarang akan terlihat seperti ini:
import androidx.compose.foundation.layout.width
@Composable
fun FavoriteCollectionCard(
modifier: Modifier = Modifier
) {
Surface(
shape = MaterialTheme.shapes.medium,
modifier = modifier
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.width(255.dp)
) {
Image(
painter = painterResource(R.drawable.fc2_nature_meditations),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.size(80.dp)
)
Text(
text = stringResource(R.string.fc2_nature_meditations)
)
}
}
}
Pratinjau sekarang akan terlihat seperti ini:
Untuk menyelesaikan composable ini, terapkan langkah-langkah berikut:
- Jadikan gambar dan teks dinamis. Teruskan argumen sebagai argumen ke fungsi composable.
- Mengubah warna ke surfaceVariant.
- Perbarui teks agar menggunakan gaya tipografi titleMedium.
- Perbarui spasi antara gambar dan teks.
Hasil akhir Anda akan terlihat seperti ini:
@Composable
fun FavoriteCollectionCard(
@DrawableRes drawable: Int,
@StringRes text: Int,
modifier: Modifier = Modifier
) {
Surface(
shape = MaterialTheme.shapes.medium,
color = MaterialTheme.colorScheme.surfaceVariant,
modifier = modifier
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.width(255.dp)
) {
Image(
painter = painterResource(drawable),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.size(80.dp)
)
Text(
text = stringResource(text),
style = MaterialTheme.typography.titleMedium,
modifier = Modifier.padding(horizontal = 16.dp)
)
}
}
}
//..
@Preview(showBackground = true, backgroundColor = 0xFFF5F0EE)
@Composable
fun FavoriteCollectionCardPreview() {
MySootheTheme {
FavoriteCollectionCard(
text = R.string.fc2_nature_meditations,
drawable = R.drawable.fc2_nature_meditations,
modifier = Modifier.padding(8.dp)
)
}
}
Lihat Pratinjau FavoriteCollectionCardPreview.
7. Baris Align your body - Pengaturan
Setelah membuat composable dasar yang ditampilkan di layar, Anda dapat mulai membuat bagian layar yang berbeda.
Mulai dengan baris "Align your body" yang dapat di-scroll.
Berikut adalah desain garis merah untuk komponen ini:
Ingat bahwa satu blok petak mewakili 8 dp. Jadi, dalam desain ini, ada spasi 16 dp sebelum item pertama, dan setelah item terakhir pada baris. Terdapat spasi 8 dp di antara setiap item.
Di Compose, Anda dapat menerapkan baris yang dapat di-scroll seperti ini menggunakan composable LazyRow
. Dokumentasi pada daftar berisi informasi selengkapnya tentang daftar Lambat seperti LazyRow
dan LazyColumn
. Untuk codelab ini, Anda hanya perlu mengetahui bahwa LazyRow
hanya merender elemen yang ditampilkan di layar, bukan semua elemen pada saat yang bersamaan, yang membantu menjaga performa aplikasi Anda.
Mulai dengan implementasi dasar LazyRow
ini:
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
@Composable
fun AlignYourBodyRow(
modifier: Modifier = Modifier
) {
LazyRow(
modifier = modifier
) {
items(alignYourBodyData) { item ->
AlignYourBodyElement(item.drawable, item.text)
}
}
}
Seperti yang dapat Anda lihat, turunan LazyRow
bukan composable. Sebagai gantinya, Anda menggunakan DSL daftar Lambat yang menyediakan metode seperti item
dan items
yang memunculkan composable sebagai item daftar. Untuk setiap item dalam alignYourBodyData
yang diberikan, Anda membuat composable AlignYourBodyElement
yang Anda terapkan sebelumnya.
Perhatikan bagaimana hal ini ditampilkan:
Spasi yang kita lihat dalam desain garis merah masih belum ada. Untuk menerapkannya, Anda harus mempelajari pengaturan.
Pada langkah sebelumnya, Anda telah mempelajari penyelarasan, yang digunakan untuk meratakan turunan penampung pada sumbu silang. Untuk Column
, sumbu silang adalah sumbu horizontal, sedangkan untuk Row
, sumbu silang adalah sumbu vertikal.
Namun, kita juga dapat membuat keputusan tentang cara menempatkan composable turunan pada sumbu utama penampung (horizontal untuk Row
, vertikal untuk Column
).
Untuk Row
, Anda dapat memilih pengaturan berikut:
Dan untuk Column
:
Selain pengaturan ini, Anda juga dapat menggunakan metode Arrangement.spacedBy()
untuk menambahkan spasi tetap di antara setiap composable turunan.
Dalam contoh, metode spacedBy
adalah satu-satunya yang perlu Anda gunakan, ketika Anda ingin menempatkan spasi 8 dp di antara setiap item dalam LazyRow
.
import androidx.compose.foundation.layout.Arrangement
@Composable
fun AlignYourBodyRow(
modifier: Modifier = Modifier
) {
LazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = modifier
) {
items(alignYourBodyData) { item ->
AlignYourBodyElement(item.drawable, item.text)
}
}
}
Sekarang desainnya terlihat seperti ini:
Anda juga perlu menambahkan padding di bagian samping LazyRow
. Dalam kasus ini, menambahkan pengubah padding sederhana tidak dapat dilakukan. Coba tambahkan padding ke LazyRow
dan lihat bagaimana perilakunya menggunakan pratinjau interaktif:
Seperti yang dapat Anda lihat, saat men-scroll, item pertama dan terakhir yang terlihat terpotong di kedua sisi layar.
Untuk mempertahankan padding yang sama, tetapi tetap men-scroll konten dalam batas daftar induk tanpa memotongnya, semua daftar akan memberikan parameter ke LazyRow
bernama contentPadding
dan menyetelnya ke 16.dp
.
import androidx.compose.foundation.layout.PaddingValues
@Composable
fun AlignYourBodyRow(
modifier: Modifier = Modifier
) {
LazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(horizontal = 16.dp),
modifier = modifier
) {
items(alignYourBodyData) { item ->
AlignYourBodyElement(item.drawable, item.text)
}
}
}
Coba pratinjau interaktif untuk melihat perbedaan yang dibuat oleh padding.
8. Petak Favorite collections - Petak Lambat
Bagian berikutnya yang akan diterapkan adalah bagian "Koleksi favorit" pada layar. Sebagai ganti satu baris, composable ini membutuhkan petak:
Anda dapat menerapkan bagian ini seperti bagian sebelumnya, dengan membuat LazyRow
dan membiarkan setiap item menyimpan Column
dengan dua instance FavoriteCollectionCard
. Namun, pada langkah ini, Anda akan menggunakan LazyHorizontalGrid
, yang memberikan pemetaan yang lebih baik dari item ke elemen petak.
Mulai dengan implementasi petak sederhana dengan dua baris tetap:
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
import androidx.compose.foundation.lazy.grid.items
@Composable
fun FavoriteCollectionsGrid(
modifier: Modifier = Modifier
) {
LazyHorizontalGrid(
rows = GridCells.Fixed(2),
modifier = modifier
) {
items(favoriteCollectionsData) { item ->
FavoriteCollectionCard(item.drawable, item.text)
}
}
}
Seperti yang dapat Anda lihat, Anda cukup mengganti LazyRow
dari langkah sebelumnya dengan LazyHorizontalGrid
. Namun, langkah ini belum akan memberikan hasil yang benar:
Petak menempati ruang sebanyak induknya, yang berarti kartu koleksi favorit direntangkan terlalu jauh secara vertikal.
Sesuaikan composable, sehingga
- Petak memiliki contentPadding horizontal 16 dp.
- Pengaturan horizontal dan vertikal berjarak 16 dp.
- Tinggi petak adalah 168 dp.
- Pengubah FavoriteCollectionCard menentukan tinggi 80 dp.
Kode final akan terlihat seperti ini:
@Composable
fun FavoriteCollectionsGrid(
modifier: Modifier = Modifier
) {
LazyHorizontalGrid(
rows = GridCells.Fixed(2),
contentPadding = PaddingValues(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = modifier.height(168.dp)
) {
items(favoriteCollectionsData) { item ->
FavoriteCollectionCard(item.drawable, item.text, Modifier.height(80.dp))
}
}
}
Pratinjau akan terlihat seperti ini:
9. Bagian beranda - Slot API
Di layar utama MySoothe, ada beberapa bagian yang mengikuti pola yang sama. Masing-masing memiliki judul, dengan beberapa konten yang bervariasi bergantung pada bagian. Berikut adalah desain garis merah yang ingin kita implementasikan:
Seperti yang dapat dilihat, setiap bagian memiliki judul dan slot. Judul memiliki beberapa informasi spasi dan gaya yang terkait dengannya. Slot dapat diisi secara dinamis dengan konten yang berbeda, tergantung pada bagian.
Untuk menerapkan penampung bagian fleksibel ini, Anda menggunakan apa yang disebut slot API. Sebelum menerapkan ini, baca bagian di halaman dokumentasi tentang tata letak berbasis slot. Hal ini akan membantu Anda memahami tata letak berbasis slot dan cara menggunakan slot API untuk membuat tata letak semacam itu.
Sesuaikan composable HomeSection
untuk menerima judul dan konten slot. Anda juga harus menyesuaikan Pratinjau terkait untuk memanggil HomeSection
ini dengan judul dan konten "Align your body":
@Composable
fun HomeSection(
@StringRes title: Int,
modifier: Modifier = Modifier,
content: @Composable () -> Unit
) {
Column(modifier) {
Text(stringResource(title))
content()
}
}
@Preview(showBackground = true, backgroundColor = 0xFFF5F0EE)
@Composable
fun HomeSectionPreview() {
MySootheTheme {
HomeSection(R.string.align_your_body) {
AlignYourBodyRow()
}
}
}
Anda dapat menggunakan parameter content
untuk slot composable. Dengan cara ini, saat menggunakan composable HomeSection
, Anda dapat menggunakan lambda di akhir untuk mengisi slot konten. Saat composable menyediakan beberapa slot untuk diisi, Anda dapat memberinya nama yang bermakna yang mewakili fungsinya dalam penampung composable yang lebih besar. Misalnya, TopAppBar
Material menyediakan slot untuk title
, navigationIcon
, dan actions
.
Mari kita lihat tampilan bagian tersebut dengan implementasi ini:
Composable Text memerlukan beberapa informasi lainnya agar sesuai dengan desain.
Perbarui composable Text agar:
- Menggunakan tipografi titleMedium.
- Spasi antara dasar teks dan bagian atas adalah 40 dp.
- Jarak antara dasar dan bagian bawah elemen adalah 16 dp.
- Padding horizontal adalah 16 dp.
Solusi akhir Anda akan terlihat seperti ini:
@Composable
fun HomeSection(
@StringRes title: Int,
modifier: Modifier = Modifier,
content: @Composable () -> Unit
) {
Column(modifier) {
Text(
text = stringResource(title),
style = MaterialTheme.typography.titleMedium,
modifier = Modifier
.paddingFromBaseline(top = 40.dp, bottom = 16.dp)
.padding(horizontal = 16.dp)
)
content()
}
}
10. Layar utama - Scroll
Setelah membuat semua elemen penyusun yang terpisah, Anda dapat menggabungkannya ke dalam implementasi layar penuh.
Berikut adalah desain yang Anda coba terapkan:
Kami hanya menempatkan kotak penelusuran dan dua bagian di bawah satu sama lain. Ada beberapa spasi yang perlu Anda tambahkan agar semuanya sesuai dengan desain. Satu composable yang belum pernah kita gunakan sebelumnya adalah Spacer
, yang membantu kita menempatkan ruang ekstra di dalam Column
. Jika akan menyetel padding Column
, Anda akan mendapatkan perilaku terpotong yang sama seperti yang kita lihat sebelumnya di petak Favorite Collections.
@Composable
fun HomeScreen(modifier: Modifier = Modifier) {
Column(modifier) {
Spacer(Modifier.height(16.dp))
SearchBar(Modifier.padding(horizontal = 16.dp))
HomeSection(title = R.string.align_your_body) {
AlignYourBodyRow()
}
HomeSection(title = R.string.favorite_collections) {
FavoriteCollectionsGrid()
}
Spacer(Modifier.height(16.dp))
}
}
Meskipun desainnya cocok dengan sebagian besar ukuran perangkat, desain harus dapat di-scroll secara vertikal jika perangkat tidak cukup tinggi, misalnya dalam mode lanskap. Hal ini mengharuskan Anda menambahkan perilaku scroll.
Seperti yang kita lihat sebelumnya, tata letak Lazy seperti LazyRow
dan LazyHorizontalGrid
secara otomatis menambahkan perilaku scroll. Namun, Anda tidak selalu memerlukan tata letak Lambat. Secara umum, Anda akan menggunakan tata letak Lambat jika memiliki banyak elemen dalam daftar atau set data besar untuk dimuat, jadi memunculkan semua item sekaligus akan mengorbankan performa dan akan memperlambat aplikasi Anda. Jika daftar hanya memiliki sejumlah elemen yang terbatas, Anda dapat memilih untuk menggunakan Column
atau Row
sederhana dan menambahkan perilaku scroll secara manual. Untuk melakukannya, gunakan pengubah verticalScroll
atau horizontalScroll
. Hal ini memerlukan ScrollState
, yang berisi status scroll saat ini, yang digunakan untuk mengubah status scroll dari luar. Dalam hal ini, Anda tidak ingin mengubah status scroll, jadi Anda cukup membuat instance ScrollState
persisten menggunakan rememberScrollState
.
Hasil akhir Anda akan terlihat seperti ini:
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
@Composable
fun HomeScreen(modifier: Modifier = Modifier) {
Column(
modifier
.verticalScroll(rememberScrollState())
) {
Spacer(Modifier.height(16.dp))
SearchBar(Modifier.padding(horizontal = 16.dp))
HomeSection(title = R.string.align_your_body) {
AlignYourBodyRow()
}
HomeSection(title = R.string.favorite_collections) {
FavoriteCollectionsGrid()
}
Spacer(Modifier.height(16.dp))
}
}
Untuk memverifikasi perilaku scroll composable, batasi tinggi Pratinjau dan jalankan dalam pratinjau interaktif:
@Preview(showBackground = true, backgroundColor = 0xFFF5F0EE, heightDp = 180)
@Composable
fun ScreenContentPreview() {
MySootheTheme { HomeScreen() }
}
11. Navigasi bawah - Material
Setelah mengimplementasikan konten layar, Anda siap untuk menambahkan dekorasi jendela. Untuk MySoothe, ada menu navigasi yang memungkinkan pengguna beralih di antara layar yang berbeda.
Pertama, implementasikan composable menu navigasi, lalu sertakan dalam aplikasi Anda.
Mari kita lihat desainnya:
Untungnya, Anda tidak perlu menerapkan seluruh composable ini sendiri dari awal. Anda dapat menggunakan composable NavigationBar
yang merupakan bagian dari library Compose Material. Di dalam composable NavigationBar
, Anda dapat menambahkan satu atau beberapa elemen NavigationBarItem
, yang kemudian akan diberi gaya secara otomatis oleh library Material.
Mulai dengan implementasi dasar navigasi bawah ini:
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Spa
@Composable
private fun SootheBottomNavigation(modifier: Modifier = Modifier) {
NavigationBar(
modifier = modifier
) {
NavigationBarItem(
icon = {
Icon(
imageVector = Icons.Default.Spa,
contentDescription = null
)
},
label = {
Text(
text = stringResource(R.string.bottom_navigation_home)
)
},
selected = true,
onClick = {}
)
NavigationBarItem(
icon = {
Icon(
imageVector = Icons.Default.AccountCircle,
contentDescription = null
)
},
label = {
Text(
text = stringResource(R.string.bottom_navigation_profile)
)
},
selected = false,
onClick = {}
)
}
}
Seperti inilah tampilan implementasi dasarnya - tidak banyak kontras antara warna konten dan warna menu navigasi.
Ada beberapa adaptasi gaya yang harus Anda buat. Pertama-tama, Anda dapat memperbarui warna latar belakang navigasi bawah dengan menetapkan parameter containerColor
-nya. Anda dapat menggunakan warna surfaceVariant dari Penetapan Tema Material untuk ini. Solusi akhir Anda akan terlihat seperti ini:
@Composable
private fun SootheBottomNavigation(modifier: Modifier = Modifier) {
NavigationBar(
containerColor = MaterialTheme.colorScheme.surfaceVariant,
modifier = modifier
) {
NavigationBarItem(
icon = {
Icon(
imageVector = Icons.Default.Spa,
contentDescription = null
)
},
label = {
Text(stringResource(R.string.bottom_navigation_home))
},
selected = true,
onClick = {}
)
NavigationBarItem(
icon = {
Icon(
imageVector = Icons.Default.AccountCircle,
contentDescription = null
)
},
label = {
Text(stringResource(R.string.bottom_navigation_profile))
},
selected = false,
onClick = {}
)
}
}
Sekarang menu navigasi akan terlihat seperti ini, perhatikan bagaimana menu tersebut memberikan lebih banyak kontras.
12. Aplikasi MySoothe - Scaffold
Untuk langkah ini, buat implementasi layar penuh, termasuk navigasi bawah. Gunakan composable Scaffold
Material. Scaffold
memberi Anda composable tingkat atas yang dapat dikonfigurasi untuk aplikasi yang menerapkan Desain Material. Terdapat slot untuk berbagai konsep Material, salah satunya adalah panel bawah. Di panel bawah ini, Anda dapat menempatkan composable navigasi bawah yang Anda buat di langkah sebelumnya.
Implementasikan composable MySootheAppPortrait()
. Ini adalah composable tingkat atas untuk aplikasi Anda, jadi Anda harus:
- Menerapkan tema Material
MySootheTheme
. - Tambahkan
Scaffold
. - Tetapkan panel bawah menjadi composable
SootheBottomNavigation
Anda. - Setel konten menjadi composable
HomeScreen
Anda.
Hasil akhir Anda seharusnya:
import androidx.compose.material3.Scaffold
@Composable
fun MySootheAppPortrait() {
MySootheTheme {
Scaffold(
bottomBar = { SootheBottomNavigation() }
) { padding ->
HomeScreen(Modifier.padding(padding))
}
}
}
Implementasi Anda kini selesai! Jika ingin memeriksa apakah versi telah diterapkan dengan cara yang sesuai untuk piksel, Anda dapat membandingkan gambar ini dengan implementasi Pratinjau Anda sendiri.
13. Kolom Samping Navigasi - Material
Saat membuat tata letak untuk aplikasi, Anda juga perlu memperhatikan seperti apa tampilannya dalam beberapa konfigurasi, termasuk mode lanskap di ponsel. Berikut adalah desain untuk aplikasi dalam mode lanskap. Perhatikan bagaimana navigasi bawah berubah menjadi kolom samping di sebelah kiri konten layar.
Untuk menerapkannya, Anda akan menggunakan composable NavigationRail
yang merupakan bagian dari library Compose Material dan memiliki implementasi serupa dengan NavigationBar
yang digunakan untuk membuat menu navigasi bawah. Di dalam composable NavigationRail, Anda akan menambahkan elemen NavigationRailItem
untuk Beranda dan Profil.
Mari kita mulai dengan implementasi dasar untuk Kolom Samping Navigasi.
import androidx.compose.material3.NavigationRail
import androidx.compose.material3.NavigationRailItem
@Composable
private fun SootheNavigationRail(modifier: Modifier = Modifier) {
NavigationRail(
) {
Column(
) {
NavigationRailItem(
icon = {
Icon(
imageVector = Icons.Default.Spa,
contentDescription = null
)
},
label = {
Text(stringResource(R.string.bottom_navigation_home))
},
selected = true,
onClick = {}
)
NavigationRailItem(
icon = {
Icon(
imageVector = Icons.Default.AccountCircle,
contentDescription = null
)
},
label = {
Text(stringResource(R.string.bottom_navigation_profile))
},
selected = false,
onClick = {}
)
}
}
}
Ada beberapa adaptasi gaya yang harus Anda buat.
- Tambahkan padding 8 dp di awal dan akhir kolom samping.
- Perbarui warna latar belakang kolom samping navigasi dengan menetapkan parameter
containerColor
-nya menggunakan warna latar belakang dari Penetapan Tema Material untuk ini. Dengan menetapkan warna latar belakang, warna ikon dan teks akan otomatis disesuaikan dengan warnaonBackground
tema. - Kolom harus mengisi tinggi maksimum.
- Tetapkan pengaturan vertikal kolom ke tengah.
- Tetapkan perataan horizontal kolom ke tengah secara horizontal.
- Tambahkan padding 8 dp di antara dua ikon.
Solusi akhir Anda akan terlihat seperti ini:
import androidx.compose.foundation.layout.fillMaxHeight
@Composable
private fun SootheNavigationRail(modifier: Modifier = Modifier) {
NavigationRail(
modifier = modifier.padding(start = 8.dp, end = 8.dp),
containerColor = MaterialTheme.colorScheme.background,
) {
Column(
modifier = modifier.fillMaxHeight(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
NavigationRailItem(
icon = {
Icon(
imageVector = Icons.Default.Spa,
contentDescription = null
)
},
label = {
Text(stringResource(R.string.bottom_navigation_home))
},
selected = true,
onClick = {}
)
Spacer(modifier = Modifier.height(8.dp))
NavigationRailItem(
icon = {
Icon(
imageVector = Icons.Default.AccountCircle,
contentDescription = null
)
},
label = {
Text(stringResource(R.string.bottom_navigation_profile))
},
selected = false,
onClick = {}
)
}
}
}
Sekarang, mari kita tambahkan Kolom Samping Navigasi ke tata letak lanskap.
Untuk versi potret aplikasi, Anda menggunakan Scaffold. Namun, untuk lanskap, Anda akan menggunakan Baris dan menempatkan kolom samping navigasi dan konten layar berdampingan satu sama lain.
@Composable
fun MySootheAppLandscape() {
MySootheTheme {
Row {
SootheNavigationRail()
HomeScreen()
}
}
}
Saat Anda menggunakan Scaffold dalam versi potret, Anda juga harus mengatur warna konten ke latar belakang untuk Anda. Untuk menetapkan warna Kolom Samping Navigasi, gabungkan Baris dalam Platform dan tetapkan ke warna latar belakang.
@Composable
fun MySootheAppLandscape() {
MySootheTheme {
Surface(color = MaterialTheme.colorScheme.background) {
Row {
SootheNavigationRail()
HomeScreen()
}
}
}
}
14. Aplikasi MySoothe - Ukuran jendela
Anda memiliki Pratinjau untuk mode lanskap yang terlihat bagus. Namun, jika Anda menjalankan aplikasi di perangkat atau emulator dan memutarnya di samping, Anda tidak akan melihat versi lanskapnya. Dengan kata lain, kita perlu memberi tahu aplikasi kapan harus menampilkan konfigurasi aplikasi yang sedang digunakan. Untuk melakukannya, gunakan fungsi calculateWindowSizeClass()
untuk melihat konfigurasi yang digunakan ponsel.
Ada tiga lebar class ukuran jendela: Rapat, Sedang, dan Diperluas. Jika aplikasi dalam mode potret, lebarnya adalah Rapat. Jika aplikasi dalam mode lanskap, lebarnya adalah Diperluas. Untuk tujuan codelab ini, Anda tidak akan menggunakan lebar Sedang.
Di Composable MySootheApp, perbarui ukuran jendela agar dapat menggunakan WindowSizeClass perangkat. Jika rapat, teruskan aplikasi dalam versi potret. Jika menggunakan orientasi lanskap, teruskan aplikasi dalam versi lanskap.
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
@Composable
fun MySootheApp(windowSize: WindowSizeClass) {
when (windowSize.widthSizeClass) {
WindowWidthSizeClass.Compact -> {
MySootheAppPortrait()
}
WindowWidthSizeClass.Expanded -> {
MySootheAppLandscape()
}
}
}
Di setContent()
, buat val bernama windowSizeClass yang disetel ke calculateWindowSize()
dan teruskan ke MySootheApp().
Karena calculateWindowSize()
masih bersifat eksperimental, Anda harus memilih class ExperimentalMaterial3WindowSizeClassApi
.
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
class MainActivity : ComponentActivity() {
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val windowSizeClass = calculateWindowSizeClass(this)
MySootheApp(windowSizeClass)
}
}
}
Sekarang - jalankan aplikasi di emulator atau perangkat Anda dan amati perubahan tampilan saat rotasi.
15. Selamat
Selamat, Anda telah berhasil menyelesaikan codelab ini dan mempelajari tata letak di Compose lebih lanjut. Melalui penerapan desain sebenarnya, Anda telah mempelajari pengubah, perataan, pengaturan, tata letak Lambat, slot API, scroll, komponen Material, dan desain khusus tata letak.
Lihat codelab lain di jalur Compose. Dan lihat contoh kode.
Dokumentasi
Untuk mendapatkan informasi selengkapnya dan panduan tentang topik ini, lihat dokumentasi berikut: