Tata letak dasar di Compose

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 mem-build composable fleksibel menggunakan API slot.

Yang akan Anda butuhkan

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:

24ff9efa75f22198.png

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 android-compose-codelabs. Untuk melakukan clone kode ini, jalankan:

$ git clone https://github.com/googlecodelabs/android-compose-codelabs

Atau, Anda dapat mendownload dua file ZIP:

Lihat kodenya

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

Mari kita pelajari lebih lanjut desainnya:

c31e78e48cc1f336.png

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.

9a0f4be94a5a206c.png

Melihat perincian, konten layar berisi tiga sub-bagian:

  • Kotak penelusuran.
  • Bagian bernama "Align your body".
  • Bagian yang disebut "Koleksi favorit".

d9bf2ca5a0939959.png

Di dalam setiap bagian, Anda juga dapat melihat beberapa komponen dengan level lebih rendah yang digunakan kembali:

  • Elemen "selaraskan tubuh Anda" yang ditampilkan dalam baris yang dapat di-scroll secara horizontal.

29bed1f813622dc.png

  • Kartu "favorite collection" (koleksi favorit) yang ditampilkan dalam petak yang dapat di-scroll secara horizontal.

cf1fe8b2d682bfca.png

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 :

6b7c2f913d189b9a.png

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.

6c6854661a89e995.png

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.material.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 parameter modifier dan meneruskannya ke TextField. 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:

c2e1eec30f36bc72.png

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.
  • Tambahkan 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.material.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:

6b7c2f913d189b9a.png

Berikut adalah langkah-langkah yang sebaiknya Anda lakukan untuk mengupdate penerapan:

  • Tambahkan ikon penelusuran. TextField berisi parameter leadingIcon yang menerima composable lain. Di dalam, Anda dapat menetapkan Icon, yang dalam hal ini berupa ikon Search. Pastikan untuk menggunakan impor Icon Compose yang tepat.
  • Setel warna latar belakang kolom teks ke warna surface MaterialTheme. Anda dapat menggunakan TextFieldDefaults.textFieldColors untuk mengganti warna tertentu.
  • Tambahkan teks placeholder "Telusuri" (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.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.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.textFieldColors(
           backgroundColor = MaterialTheme.colors.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 data TextFieldDefaults, tempat Anda hanya mengubah warna yang berbeda. Dalam hal ini, itu hanya warna latar belakang.
  • Anda menetapkan tinggi minimum, bukan tinggi tetap. Ini adalah pendekatan yang direkomendasikan, sehingga kolom teks masih dapat bertambah besar ketika pengguna, misalnya, meningkatkan ukuran font di setelan sistem.

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 redline di sampingnya:

29bed1f813622dc.png 9d11e16a8817686f.png

Desain redline kini juga berisi spasi berorientasi dasar. 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 H3.

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 memindahkannya untuk menggunakan parameter yang disediakan di composable AlightYourBodyElement untuk membuatnya dinamis.

Lihat pratinjau composable ini:

b9686f83eb73c542.png

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.

Gambar juga harus diskalakan dengan benar. Untuk melakukannya, kita dapat menggunakan parameter contentScale Image. Ada beberapa opsi, terutama:

5f17f07fcd0f1dc.png

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:

6576ed1e8b1cde30.png

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:

  • AwalAtas
  • TopCenter (TengahAtas)
  • TopEnd
  • AwalTengah
  • Tengah
  • 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, 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 yang di-hard code.
  • Update teks agar menggunakan gaya tipografi yang tepat.
  • Update spasi dasar elemen teks.

Setelah selesai menerapkan langkah-langkah ini, kode Anda akan terlihat seperti ini:

import androidx.compose.foundation.layout.paddingFromBaseline

@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),
           style = MaterialTheme.typography.h3,
           modifier = Modifier.paddingFromBaseline(
               top = 24.dp, bottom = 8.dp
           )
       )
   }
}

@Preview(showBackground = true, backgroundColor = 0xFFF0EAE2)
@Composable
fun AlignYourBodyElementPreview() {
   MySootheTheme {
       AlignYourBodyElement(
           text = R.string.ab1_inversions,
           drawable = R.drawable.ab1_inversions,
           modifier = Modifier.padding(8.dp)
       )
   }
}

6. Kartu Favorite collection - Platform Material

Composable berikutnya yang akan diimplementasikan sama dengan elemen "Align the body". Berikut adalah desainnya, termasuk redline:

71fcfc487ef8c02a.png

f2f4fb696389ba4f.png

Dalam hal ini, ukuran penuh composable disediakan. Anda dapat melihat bahwa teks tersebut sekali lagi harus H3.

Penampung ini memiliki semacam warna latar belakang, yang berbeda dengan latar belakang pada keseluruhan layar. Ada juga sudut yang membulat. Karena desainer tidak menentukan warna, kita dapat berasumsi bahwa warna akan ditentukan oleh tema. Untuk penampung tersebut, kita 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.material.Surface

@Composable
fun FavoriteCollectionCard(
   modifier: Modifier = Modifier
) {
   Surface(
       shape = MaterialTheme.shapes.small,
       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:

5584e459f9838f8b.png

Selanjutnya, terapkan hal yang dipelajari pada langkah sebelumnya. Menetapkan ukuran gambar dan memangkasnya dalam penampung. Tetapkan lebar Row, dan sejajarkan turunannya secara vertikal. 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.small,
       modifier = modifier
   ) {
       Row(
           verticalAlignment = Alignment.CenterVertically,
           modifier = Modifier.width(192.dp)
       ) {
           Image(
               painter = painterResource(R.drawable.fc2_nature_meditations),
               contentDescription = null,
               contentScale = ContentScale.Crop,
               modifier = Modifier.size(56.dp)
           )
           Text(
               text = stringResource(R.string.fc2_nature_meditations)
           )
       }
   }
}

Pratinjau sekarang akan terlihat seperti ini:

e0afeb1658a6d82a.png

Untuk menyelesaikan composable ini, terapkan langkah-langkah berikut:

  • Jadikan gambar dan teks dinamis. Teruskan argumen sebagai argumen ke fungsi composable.
  • Update teks agar menggunakan gaya tipografi yang tepat.
  • Update 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.small,
       modifier = modifier
   ) {
       Row(
           verticalAlignment = Alignment.CenterVertically,
           modifier = Modifier.width(192.dp)
       ) {
           Image(
               painter = painterResource(drawable),
               contentDescription = null,
               contentScale = ContentScale.Crop,
               modifier = Modifier.size(56.dp)
           )
           Text(
               text = stringResource(text),
               style = MaterialTheme.typography.h3,
               modifier = Modifier.padding(horizontal = 16.dp)
           )
       }
   }
}

//..

@Preview(showBackground = true, backgroundColor = 0xFFF0EAE2)
@Composable
fun FavoriteCollectionCardPreview() {
   MySootheTheme {
       FavoriteCollectionCard(
           text = R.string.fc2_nature_meditations,
           drawable = R.drawable.fc2_nature_meditations,
           modifier = Modifier.padding(8.dp)
       )
   }
}

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 "Selaraskan tubuh Anda" yang dapat di-scroll.

25089e1f3e5eab4e.gif

Berikut adalah desain redline untuk komponen ini:

9d943fabcb5ae632.png

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:

b88f30efe9067f53.png

Spasi yang kita lihat dalam desain redline masih hilang. 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:

c1e6c40e30136af2.gif

Dan untuk Column:

df69881d07b064d0.gif

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:

c29a8ee73f218868.png

Anda juga perlu menambahkan padding di bagian samping LazyRow. Menambahkan pengubah padding sederhana tidak akan melakukan trik dalam kasus ini. Coba tambahkan padding ke LazyRow dan lihat bagaimana perilakunya:

6b3f390040e2b7fd.gif

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 bernama contentPadding.

@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)
       }
   }
}

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:

4378867d758590ae.gif

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, ini belum akan memberikan hasil yang benar:

e51beb5c00457902.png

Petak menempati ruang sebanyak induknya, yang berarti kartu koleksi favorit direntangkan terlalu jauh secara vertikal. Sesuaikan composable, sehingga sel petak memiliki ukuran dan spasi yang benar di antara sel tersebut.

Hasil Anda akan terlihat seperti ini:

@Composable
fun FavoriteCollectionsGrid(
   modifier: Modifier = Modifier
) {
   LazyHorizontalGrid(
       rows = GridCells.Fixed(2),
       contentPadding = PaddingValues(horizontal = 16.dp),
       horizontalArrangement = Arrangement.spacedBy(8.dp),
       verticalArrangement = Arrangement.spacedBy(8.dp),
       modifier = modifier.height(120.dp)
   ) {
       items(favoriteCollectionsData) { item ->
           FavoriteCollectionCard(
               drawable = item.drawable,
               text = item.text,
               modifier = Modifier.height(56.dp)
           )
       }
   }
}

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 yang ingin kita implementasikan:

2c0bc456d50bb078.png

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 = 0xFFF0EAE2)
@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:

d824b60e650deeb.png

Composable Text memerlukan beberapa informasi lainnya agar sesuai dengan desain. Lakukan update agar:

  • Kode ini ditampilkan dengan huruf besar semua (petunjuk: Anda dapat menggunakan metode uppercase() dari String untuk ini).
  • Menggunakan tipografi H2.
  • Class ini memiliki padding yang sesuai dengan desain redline.

Solusi akhir Anda akan terlihat seperti ini:

import java.util.*

@Composable
fun HomeSection(
   @StringRes title: Int,
   modifier: Modifier = Modifier,
   content: @Composable () -> Unit
) {
   Column(modifier) {
       Text(
           text = stringResource(title).uppercase(Locale.getDefault()),
           style = MaterialTheme.typography.h2,
           modifier = Modifier
               .paddingFromBaseline(top = 40.dp, bottom = 8.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:

a535e10437e9df31.png

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.rememberScrollState
import androidx.compose.foundation.verticalScroll

@Composable
fun HomeScreen(modifier: Modifier = Modifier) {
   Column(
       modifier
           .verticalScroll(rememberScrollState())
           .padding(vertical = 16.dp)
   ) {
       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 = 0xFFF0EAE2, heightDp = 180)
@Composable
fun ScreenContentPreview() {
   MySootheTheme { HomeScreen() }
}

11. Navigasi bawah - Material

Setelah mengimplementasikan konten layar, Anda siap untuk menambahkan dekorasi jendela Untuk MySoothe, ada navigasi bawah yang memungkinkan pengguna beralih di antara layar yang berbeda.

Pertama, implementasikan composable navigasi bawah ini sendiri, lalu sertakan dalam aplikasi Anda.

Mari kita lihat desainnya:

2f42ad2b882885f8.png

Untungnya, Anda tidak perlu menerapkan seluruh composable ini sendiri dari awal. Anda dapat menggunakan composable BottomNavigation yang merupakan bagian dari library Compose Material. Di dalam composable BottomNavigation, Anda dapat menambahkan satu atau beberapa elemen BottomNavigationItem, yang kemudian akan diberi gaya secara otomatis oleh library Material.

Mulai dengan implementasi dasar navigasi bawah ini:

import androidx.compose.material.BottomNavigation
import androidx.compose.material.BottomNavigationItem
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Spa

@Composable
private fun SootheBottomNavigation(modifier: Modifier = Modifier) {
   BottomNavigation(modifier) {
       BottomNavigationItem(
           icon = {
               Icon(
                   imageVector = Icons.Default.Spa,
                   contentDescription = null
               )
           },
           label = {
               Text(stringResource(R.string.bottom_navigation_home))
           },
           selected = true,
           onClick = {}
       )
       BottomNavigationItem(
           icon = {
               Icon(
                   imageVector = Icons.Default.AccountCircle,
                   contentDescription = null
               )
           },
           label = {
               Text(stringResource(R.string.bottom_navigation_profile))
           },
           selected = false,
           onClick = {}
       )
   }
}

Penerapan dasar ini terlihat seperti:

5bdb7729d75e1a72.png

Ada beberapa adaptasi gaya yang harus Anda buat. Pertama-tama, Anda dapat mengupdate warna latar belakang navigasi bawah dengan menetapkan parameter backgroundColor-nya. Anda dapat menggunakan warna latar belakang dari tema Material untuk ini. Dengan menetapkan warna latar belakang, warna ikon dan teks akan otomatis disesuaikan dengan warna onBackground tema. Solusi akhir Anda akan terlihat seperti ini:

@Composable
private fun SootheBottomNavigation(modifier: Modifier = Modifier) {
   BottomNavigation(
       backgroundColor = MaterialTheme.colors.background,
       modifier = modifier
   ) {
       BottomNavigationItem(
           icon = {
               Icon(
                   imageVector = Icons.Default.Spa,
                   contentDescription = null
               )
           },
           label = {
               Text(stringResource(R.string.bottom_navigation_home))
           },
           selected = true,
           onClick = {}
       )
       BottomNavigationItem(
           icon = {
               Icon(
                   imageVector = Icons.Default.AccountCircle,
                   contentDescription = null
               )
           },
           label = {
               Text(stringResource(R.string.bottom_navigation_profile))
           },
           selected = false,
           onClick = {}
       )
   }
}

12. Aplikasi MySoothe - Scaffold

Untuk langkah terakhir ini, buat implementasi layar penuh, termasuk navigasi bawah. Menggunakan 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.

Mengimplementasikan composable MySootheApp. 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.material.Scaffold

@Composable
fun MySootheApp() {
   MySootheTheme {
       Scaffold(
           bottomBar = { SootheBottomNavigation() }
       ) { padding ->
           HomeScreen(Modifier.padding(padding))
       }
   }
}

Implementasi Anda kini selesai. Jika ingin memeriksa apakah versi telah diterapkan dengan cara yang sempurna untuk piksel, Anda dapat mendownload gambar berikut, dan membandingkannya dengan implementasi Pratinjau Anda sendiri.

24ff9efa75f22198.png

13. 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, dan komponen Material.

Lihat codelab lain di jalur Compose. Dan lihat contoh kode.

Dokumentasi

Untuk mendapatkan informasi selengkapnya dan panduan tentang topik ini, lihat dokumentasi berikut: