Menambahkan Compose ke aplikasi berbasis View

1. Sebelum memulai

Sejak awal, Jetpack Compose didesain dengan interoperabilitas View, yang berarti bahwa Compose dan sistem View dapat berbagi resource dan bekerja sama secara berdampingan untuk menampilkan UI. Fungsi ini memungkinkan Anda menambahkan Compose ke aplikasi berbasis View yang ada. Artinya, Compose dan View dapat berdampingan dalam codebase hingga seluruh aplikasi Anda sepenuhnya menggunakan Compose.

Dalam codelab ini, Anda akan mengubah item daftar berbasis tampilan di aplikasi Juice Tracker menjadi Compose. Jika mau, Anda dapat mengonversi sendiri tampilan Juice Tracker lainnya.

Jika memiliki aplikasi dengan UI berbasis View, Anda mungkin tidak ingin menulis ulang seluruh UI-nya sekaligus. Codelab ini membantu Anda mengonversi satu tampilan di UI berbasis tampilan menjadi elemen Compose.

Prasyarat

  • Pemahaman tentang UI berbasis View.
  • Pengetahuan tentang cara membuat aplikasi menggunakan UI berbasis View.
  • Pengalaman dengan sintaksis Kotlin, termasuk lambda.
  • Pengetahuan tentang cara membuat aplikasi di Jetpack Compose.

Yang akan Anda pelajari

  • Cara menambahkan Compose ke layar yang ada yang dibuat dengan tampilan Android.
  • Cara melihat pratinjau Composable yang ditambahkan ke aplikasi berbasis View.

Yang akan Anda buat

  • Anda mengonversi item daftar berbasis View menjadi Compose di aplikasi Juice Tracker.

2. Ringkasan aplikasi awal

Codelab ini menggunakan kode solusi aplikasi Juice Tracker dari Membuat Aplikasi Android dengan View sebagai kode awal. Aplikasi awal telah menyimpan data menggunakan library persistensi Room. Pengguna dapat menambahkan info tentang jus ke database aplikasi, seperti nama jus, deskripsi, warna, dan rating.

Layar ponsel akan menampilkan item jus dengan detail dan rating

Dalam codelab ini, Anda akan mengonversi item daftar berbasis tampilan menjadi Compose.

Item daftar berisi detail jus

Mendownload kode awal untuk codelab ini

Untuk memulai, download kode awal:

Atau, Anda dapat membuat clone repositori GitHub untuk kode tersebut:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-juice-tracker.git
$ cd basic-android-kotlin-compose-training-juice-tracker
$ git checkout views

Anda dapat menjelajahi kode di repositori GitHub JuiceTracker.

3. Menambahkan library Jetpack Compose

Karena Recollect, Compose, dan View dapat muncul bersamaan di layar tertentu, maka Anda dapat memiliki beberapa elemen UI di Compose dan elemen lainnya di sistem View. Misalnya, Anda hanya dapat memiliki daftar di Compose, sedangkan bagian layar lainnya ada di sistem View.

Selesaikan langkah-langkah berikut untuk menambahkan library Compose ke aplikasi Juice Tracker.

  1. Buka Juice Tracker di Android Studio.
  2. Buka build.gradle.kts tingkat aplikasi.
  3. Di dalam blok buildFeatures, tambahkan flag compose = true.
buildFeatures {
    //...
    // Enable Jetpack Compose for this module
    compose = true
}

Flag ini memungkinkan Android Studio berfungsi dengan Compose. Anda belum melakukan langkah ini di codelab sebelumnya karena Android Studio otomatis membuat kode ini saat Anda membuat project template Android Studio Compose baru.

  1. Di bagian buildFeatures, tambahkan blok composeOptions.
  2. Di dalam blok, tetapkan kotlinCompilerExtensionVersion ke "1.5.1" untuk menetapkan versi compiler Kotlin.
composeOptions {
    kotlinCompilerExtensionVersion = "1.5.1"
}
  1. Di bagian dependencies, tambahkan dependensi Compose. Anda memerlukan dependensi berikut untuk menambahkan Compose ke aplikasi berbasis View. Dependensi ini membantu mengintegrasikan Compose dengan Aktivitas, menambahkan library komponen desain Compose, mendukung tema Compose Jetpack, dan menyediakan alat untuk dukungan IDE yang lebih baik.
dependencies {
    implementation(platform("androidx.compose:compose-bom:2023.06.01"))
    // other dependencies
    // Compose
    implementation("androidx.activity:activity-compose:1.7.2")
    implementation("androidx.compose.material3:material3")
    implementation("com.google.accompanist:accompanist-themeadapter-material3:0.28.0")

    debugImplementation("androidx.compose.ui:ui-tooling")
}

Menambahkan ComposeView

ComposeView adalah Android View yang dapat menghosting konten UI Jetpack Compose. Gunakan setContent untuk menyediakan fungsi composable konten untuk tampilan.

  1. Buka layout/list_item.xml, lalu lihat pratinjau di tab Split.

Di akhir codelab ini, Anda akan mengganti tampilan ini dengan composable.

f85c6002df3265e0.png

  1. Di JuiceListAdapter.kt, untuk mengatasi error, hapus ListItemBinding dari mana saja. Di class JuiceListViewHolder, ganti binding.root dengan composeView.
import androidx.compose.ui.platform.ComposeView

class JuiceListViewHolder(
    private val onEdit: (Juice) -> Unit,
    private val onDelete: (Juice) -> Unit
): RecyclerView.ViewHolder(composeView)

Untuk mengatasi error ini, Anda harus menghapus ListItemBinding dari mana saja.

  1. Di folder onCreateViewHolder(), perbarui fungsi return() agar cocok dengan kode berikut:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): JuiceListViewHolder {
   return JuiceListViewHolder(
       ComposeView(parent.context),
       onEdit,
       onDelete
   )
}
  1. Di class JuiceListViewHolder, hapus semua variabel private dan hapus juga semua kode dari fungsi bind(). Class JuiceListViewHolder Anda sekarang terlihat seperti kode berikut:
class JuiceListViewHolder(
    private val onEdit: (Juice) -> Unit,
    private val onDelete: (Juice) -> Unit
) : RecyclerView.ViewHolder(composeView) {

   fun bind(juice: Juice) {

   }
}
  1. Pada tahap ini, Anda dapat menghapus impor com.example.juicetracker.databinding.ListItemBinding dan android.view.LayoutInflater.
// Delete
import com.example.juicetracker.databinding.ListItemBinding
import android.view.LayoutInflater
  1. Hapus file layout/list_item.xml.
  2. Pilih OK di dialog Delete.

86dd7cba7e181e54.png

4. Menambahkan fungsi composable

Selanjutnya, Anda akan membuat composable yang memunculkan item daftar. Composable ini menggunakan Juice dan dua fungsi callback untuk mengedit dan menghapus item daftar.

  1. Di JuiceListAdapter.kt, setelah definisi class JuiceListAdapter, buat fungsi composable yang bernama ListItem().
  2. Buat fungsi ListItem() menerima objek Juice dan callback lambda untuk dihapus.
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier

@Composable
fun ListItem(
    input: Juice,
    onDelete: (Juice) -> Unit,
    modifier: Modifier = Modifier
) {
}

Lihat pratinjau item daftar yang ingin Anda buat. Tombol ini berisi ikon jus, detail jus, dan ikon tombol hapus. Anda akan segera menerapkan komponen ini.

cf3b235dcb93e998.png

Membuat composable ikon Juice

  1. Di JuiceListAdapter.kt, setelah composable ListItem(), buat fungsi composable lain yang disebut JuiceIcon() yang menggunakan color dan Modifier.
@Composable
fun JuiceIcon(color: String, modifier: Modifier = Modifier) {

}
  1. Di dalam fungsi JuiceIcon(), tambahkan variabel untuk color dan deskripsi konten seperti yang ditunjukkan pada kode berikut:
@Composable
fun JuiceIcon(color: String, modifier: Modifier = Modifier) {
   val colorLabelMap = JuiceColor.values().associateBy { stringResource(it.label) }
   val selectedColor = colorLabelMap[color]?.let { Color(it.color) }
   val juiceIconContentDescription = stringResource(R.string.juice_color, color)

}

Dengan menggunakan variabel colorLabelMap dan selectedColor, Anda akan mengambil resource warna yang terkait dengan pilihan pengguna.

  1. Menambahkan tata letak Box untuk menampilkan dua ikon ic_juice_color dan ic_juice_clear yang saling bertumpuk. Ikon ic_juice_color memiliki tint dan diposisikan di tengah.
import androidx.compose.foundation.layout.Box

Box(
   modifier.semantics {
       contentDescription = juiceIconContentDescription
   }
) {
   Icon(
       painter = painterResource(R.drawable.ic_juice_color),
       contentDescription = null,
       tint = selectedColor ?: Color.Red,
       modifier = Modifier.align(Alignment.Center)
   )
   Icon(painter = painterResource(R.drawable.ic_juice_clear), contentDescription = null)
}

Karena Anda sudah memahami penerapan composable, maka detail cara penerapannya tidak disediakan.

  1. Tambahkan fungsi untuk melihat pratinjau JuiceIcon(). Teruskan warna sebagai Yellow.
import androidx.compose.ui.tooling.preview.Preview

@Preview
@Composable
fun PreviewJuiceIcon() {
    JuiceIcon("Yellow")
}

Pratinjau ikon jus dengan warna kuning

Membuat composable detail jus

Di JuiceListAdapter.kt, Anda harus menambahkan fungsi composable lain untuk menampilkan detail jus. Anda juga memerlukan tata letak kolom untuk menampilkan dua composable Text untuk nama dan deskripsi, serta indikator rating. Caranya, selesaikan langkah-langkah berikut:

  1. Tambahkan fungsi composable bernama JuiceDetails() yang menggunakan objek Juice dan Modifier, serta composable teks untuk nama jus dan composable untuk deskripsi jus seperti yang ditunjukkan dalam kode berikut:
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.ui.text.font.FontWeight

@Composable
fun JuiceDetails(juice: Juice, modifier: Modifier = Modifier) {
   Column(modifier, verticalArrangement = Arrangement.Top) {
       Text(
           text = juice.name,
           style = MaterialTheme.typography.h5.copy(fontWeight = FontWeight.Bold),
       )
       Text(juice.description)
       RatingDisplay(rating = juice.rating, modifier = Modifier.padding(top = 8.dp))
   }
}
  1. Untuk mengatasi error referensi yang belum terselesaikan, buat fungsi composable yang bernama RatingDisplay().

4018a1be2b3e7399.png

Di sistem View, Anda memiliki RatingBar untuk menampilkan batang rating berikut. Compose tidak memiliki composable batang rating sehingga Anda harus menerapkan elemen ini dari awal.

  1. Tentukan fungsi RatingDisplay() untuk menampilkan bintang sesuai rating. Fungsi composable ini menampilkan jumlah bintang berdasarkan rating.

Kotak rating dengan empat bintang

import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.pluralStringResource

@Composable
fun RatingDisplay(rating: Int, modifier: Modifier = Modifier) {
   val displayDescription = pluralStringResource(R.plurals.number_of_stars, count = rating)
   Row(
       // Content description is added here to support accessibility
       modifier.semantics {
           contentDescription = displayDescription
       }
   ) {
       repeat(rating) {
           // Star [contentDescription] is null as the image is for illustrative purpose
           Image(
               modifier = Modifier.size(32.dp),
               painter = painterResource(R.drawable.star),
               contentDescription = null
           )
       }
   }
}

Untuk membuat drawable bintang di Compose, Anda harus membuat aset vektor bintang.

  1. Di panel Project, klik kanan drawable > New > Vector Asset.

e3b2bd6a495bc9.png

  1. Pada dialog Asset Studio, telusuri ikon bintang. Pilih ikon bintang yang terisi.

Dialog Select icon dengan ikon awal dipilih

  1. Ubah nilai warna bintang menjadi 625B71.

Dialog Asset studio dengan konfigurasi aset dan warna vektor

  1. Klik Next > Finish.
  2. Perhatikan bahwa drawable akan muncul di folder res/drawable.

Panel project di Android Studio mengarah ke folder res drawable

  1. Tambahkan composable pratinjau untuk melihat pratinjau composable JuiceDetails.
@Preview
@Composable
fun PreviewJuiceDetails() {
    JuiceDetails(Juice(1, "Sweet Beet", "Apple, carrot, beet, and lemon", "Red", 4))
}

dengan deskripsi nama jus dan kolom rating bintang

Membuat composable tombol hapus

  1. Di JuiceListAdapter.kt, tambahkan fungsi composable lain bernama DeleteButton() yang menggunakan fungsi callback lambda dan Pengubah.
  2. Tetapkan lambda ke argumen onClick lalu teruskan Icon() seperti yang ditunjukkan dalam kode berikut:
import androidx.compose.ui.res.painterResource
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton

@Composable
fun DeleteButton(onDelete: () -> Unit, modifier: Modifier = Modifier) {
    IconButton(
        onClick = { onDelete() },
        modifier = modifier
    ) {
        Icon(
            painter = painterResource(R.drawable.ic_delete),
            contentDescription = stringResource(R.string.delete)
        )
    }
}
  1. Menambahkan fungsi pratinjau untuk melihat pratinjau tombol hapus.
@Preview
@Composable
fun PreviewDeleteIcon() {
    DeleteButton({})
}

Pratinjau Android Studio dari ikon hapus

5. Mengimplementasikan fungsi ListItem

Setelah memiliki semua composable yang diperlukan untuk menampilkan item daftar, Anda dapat mengaturnya dalam tata letak. Perhatikan fungsi ListItem() yang sudah Anda tentukan di langkah sebelumnya.

@Composable
fun ListItem(
   input: Juice,
   onEdit: (Juice) -> Unit,
   onDelete: (Juice) -> Unit,
   modifier: Modifier = Modifier
) {
}

Di JuiceListAdapter.kt, selesaikan langkah-langkah berikut untuk menerapkan fungsi ListItem().

  1. Tambahkan tata letak Row di dalam lambda Mdc3Theme {}.
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import com.google.accompanist.themeadapter.material3.Mdc3Theme

Mdc3Theme {
   Row(
       modifier = modifier,
       horizontalArrangement = Arrangement.SpaceBetween
   ) {

   }
}
  1. Di dalam lambda Row, panggil tiga composable JuiceIcon, JuiceDetails, DeleteButton yang Anda buat sebagai elemen turunan.
JuiceIcon(input.color)
JuiceDetails(input, Modifier.weight(1f))
DeleteButton({})

Dengan meneruskan Modifier.weight(1f) ke composable JuiceDetails(), detail jus akan mengisi ruang horizontal yang tersisa setelah mengukur elemen turunan tanpa bobot.

  1. Teruskan lambda dan pengubah onDelete(input) dengan perataan atas sebagai parameter ke composable DeleteButton.
DeleteButton(
   onDelete = {
       onDelete(input)
   },
   modifier = Modifier.align(Alignment.Top)
)
  1. Tulis fungsi pratinjau untuk melihat pratinjau composable ListItem.
@Preview
@Composable
fun PreviewListItem() {
   ListItem(Juice(1, "Sweet Beet", "Apple, carrot, beet, and lemon", "Red", 4), {})
}

Pratinjau item daftar Android Studio dengan detail jus bit manis

  1. Ikat composable ListItem ke holder tampilan. Panggil onEdit(input) di dalam fungsi lambda clickable() untuk membuka dialog edit saat item daftar diklik.

Di class JuiceListViewHolder, di bagian dalam fungsi bind(), Anda harus menghosting composable. Anda menggunakan ComposeView, yang merupakan Android View yang dapat menghosting konten UI Compose menggunakan metode setContent.

fun bind(input: Juice) {
    composeView.setContent {
        ListItem(
            input,
            onDelete,
            modifier = Modifier
                .fillMaxWidth()
                .clickable {
                    onEdit(input)
                }
                .padding(vertical = 8.dp, horizontal = 16.dp),
       )
   }
}
  1. Jalankan aplikasi. Tambahkan jus favorit Anda. Perhatikan item daftar compose yang bersinar.

layar ponsel dengan detail jus yang terisi di dialog entri. Layar ponsel menampilkan satu jus dalam daftar

Selamat! Anda baru saja membuat aplikasi interoperabilitas Compose pertama yang menggunakan elemen Compose di aplikasi berbasis tampilan.

6. Mendapatkan kode solusi

Untuk mendownload kode codelab yang sudah selesai, Anda dapat menggunakan perintah git berikut:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-juice-tracker.git
$ cd basic-android-kotlin-compose-training-juice-tracker
$ git checkout views-with-compose

Atau, Anda dapat mendownload repositori sebagai file ZIP, lalu mengekstraknya, dan membukanya di Android Studio.

Jika Anda ingin melihat kode solusi, lihat di GitHub.

7. Mempelajari lebih lanjut

Dokumentasi Developer Android

Codelab [Menengah]