Tutorial

Tutorial Jetpack Compose

Jetpack Compose adalah toolkit modern untuk mem-build UI Android native. Jetpack Compose menyederhanakan dan mempercepat pengembangan UI di Android dengan kode yang lebih sedikit, alat yang canggih, dan API Kotlin yang intuitif.

Dalam tutorial ini, Anda akan membuat komponen UI sederhana dengan fungsi deklaratif. Anda tidak akan mengedit tata letak XML apa pun atau menggunakan Layout Editor. Sebagai gantinya, Anda akan memanggil fungsi Jetpack Compose untuk memberi tahu elemen apa yang Anda inginkan, selebihnya akan ditangani oleh compiler Compose.

Pratinjau Lengkap
Pratinjau Lengkap

Modul 1: Fungsi yang dapat dikomposisi

Jetpack Compose di-build berdasarkan fungsi yang dapat dikomposisi. Fungsi ini memungkinkan Anda menentukan UI aplikasi Anda secara terprogram dengan menjelaskan tampilan dan penyediaan dependensi data, bukan berfokus pada proses konstruksi UI (memulai elemen, melampirkannya ke induk, dll.). Untuk mem-build fungsi yang dapat dikomposisi, cukup tambahkan anotasi @Composable ke nama fungsi.

Menambahkan elemen teks

Untuk memulai, download versi terbaru Android Studio Arctic Fox, dan buat aplikasi menggunakan template Empty Compose Activity. Template default sudah berisi beberapa elemen Compose, tetapi mari kita mem-build ini langkah demi langkah.

Pertama, kita akan menampilkan teks “Halo dunia!” dengan menambahkan elemen teks di dalam metode onCreate. Anda dapat melakukannya dengan menentukan blok konten, dan memanggil fungsi Text(). Blok setContent menentukan tata letak aktivitas tempat kita memanggil fungsi yang dapat dikomposisi. Fungsi yang dapat dikomposisi hanya bisa dipanggil dari fungsi lain yang dapat dikomposisi.

Jetpack Compose menggunakan plugin compiler Kotlin untuk mengubah fungsi yang dapat dikomposisi ini menjadi elemen UI aplikasi. Misalnya, fungsi Text() yang ditetapkan oleh library Compose UI akan menampilkan label teks di layar.

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Text("Hello world!")
        }
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau

Menentukan fungsi yang dapat dikomposisi

Untuk membuat fungsi yang dapat dikomposisi, tambahkan anotasi @Composable. Untuk mencoba ini, tentukan fungsi MessageCard() yang mendapatkan nama dan menggunakan nama tersebut untuk mengonfigurasi elemen teks.

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MessageCard("Android")
        }
    }
}

@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

  
tampilkan pratinjau
sembunyikan pratinjau

Melihat pratinjau fungsi Anda di Android Studio

Android Studio memungkinkan Anda melihat pratinjau fungsi yang dapat dikomposisi dalam IDE, bukan menginstal aplikasi ke perangkat Android atau emulator. Fungsi yang dapat dikomposisi harus menyediakan nilai default untuk setiap parameter. Karena alasan ini, Anda tidak dapat melihat pratinjau fungsi MessageCard() secara langsung. Sekarang, mari kita buat fungsi kedua bernama PreviewMessageCard(), yang akan memanggil MessageCard() dengan parameter yang sesuai. Tambahkan anotasi @Preview sebelum @Composable.

@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}
  
tampilkan pratinjau
sembunyikan pratinjau

Mem-build ulang project Anda. Aplikasi itu sendiri tidak berubah, karena fungsi PreviewMessageCard() baru tidak dipanggil di mana pun, tetapi Android Studio menambahkan jendela pratinjau. Jendela ini menampilkan pratinjau elemen UI yang dibuat oleh fungsi yang dapat dikomposisi yang ditandai dengan anotasi @Preview. Untuk memperbarui pratinjau kapan pun, klik tombol muat ulang di bagian atas jendela pratinjau.

Gambar 1. Menggunakan Android Studio untuk melihat pratinjau fungsi yang dapat dikomposisi.
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Text("Hello world!")
        }
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MessageCard("Android")
        }
    }
}

@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}
  
tampilkan pratinjau
sembunyikan pratinjau
Gambar 1. Menggunakan Android Studio untuk melihat pratinjau fungsi yang dapat dikomposisi.

Modul 2: Tata Letak

Elemen UI bersifat hierarkis, dengan elemen satu berada di dalam elemen lainnya. Di Compose, Anda mem-build hierarki UI dengan memanggil fungsi yang dapat dikomposisi dari fungsi yang dapat dikomposisi lainnya.

Menambahkan beberapa teks

Sejauh ini, kita telah mem-build fungsi dan pratinjau pertama yang dapat dikomposisi. Untuk menemukan kemampuan Jetpack Compose lainnya, kita akan mem-build layar pesan sederhana yang berisi daftar pesan yang dapat diperluas dengan beberapa animasi.
Mari mulai dengan mengisi pesan kita, dengan menampilkan nama penulis dan konten pesannya. Kita perlu mengubah parameter yang dapat dikomposisi terlebih dahulu untuk menerima objek Message, bukan String, serta menambahkan Text yang dapat dikomposisi lainnya di dalam MessageCard yang dapat dikomposisi. Pastikan Anda juga mengupdate pratinjau:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MessageCard(Message("Android", "Jetpack Compose"))
        }
    }
}

data class Message(val author: String, val body: String)

@Composable
fun MessageCard(msg: Message) {
    Text(text = msg.author)
    Text(text = msg.body)
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard(
        msg = Message("Colleague", "Hey, take a look at Jetpack Compose, it's great!")
    )
}

  
tampilkan pratinjau
sembunyikan pratinjau

Kode ini membuat dua elemen teks di dalam tampilan konten. Namun, karena informasi tentang cara mengaturnya belum disediakan, elemen teks tersebut digambar di atas satu sama lainnya, sehingga membuat teks tidak dapat dibaca.

Menggunakan Kolom

Fungsi Column memungkinkan Anda menumpuk elemen secara vertikal. Tambahkan Column ke fungsi MessageCard().
Anda dapat menggunakan Baris untuk mengatur item secara horizontal dan Box untuk menumpuk elemen.

@Composable
fun MessageCard(msg: Message) {
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}

tampilkan pratinjau
sembunyikan pratinjau

Menambahkan elemen gambar

Mari kita mengisi kartu pesan dengan menambahkan gambar profil pengirim. Gunakan Pengelola Resource untuk mengimpor gambar dari galeri foto Anda atau gunakan yang ini. Tambahkan composable Row agar memiliki desain yang terstruktur dengan baik dan composable Image di dalamnya:

@Composable
fun MessageCard(msg: Message) {
    Row {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
        )
    
       Column {
            Text(text = msg.author)
            Text(text = msg.body)
        }
  
    }
  
}
  
tampilkan pratinjau
sembunyikan pratinjau

Mengonfigurasi tata letak Anda

Tata letak pesan kita memiliki struktur yang tepat, tetapi elemennya tidak diberi spasi dengan baik dan gambarnya terlalu besar! Untuk mendekorasi atau mengonfigurasi komponen, Compose menggunakan pengubah. Modifier memungkinkan Anda mengubah ukuran, tata letak, tampilan, atau interaksi tingkat tinggi composable, seperti membuat elemen menjadi dapat diklik. Anda dapat merangkainya untuk membuat composable yang lebih berisi. Mari kita gunakan beberapa di antaranya untuk membuat tata letak lebih bagus:

@Composable
fun MessageCard(msg: Message) {
    // Add padding around our message
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
            modifier = Modifier
                // Set image size to 40 dp
                .size(40.dp)
                // Clip image to be shaped as a circle
                .clip(CircleShape)
        )

        // Add a horizontal space between the image and the column
        Spacer(modifier = Modifier.width(8.dp))

        Column {
            Text(text = msg.author)
            // Add a vertical space between the author and message texts
            Spacer(modifier = Modifier.height(4.dp))
            Text(text = msg.body)
        }
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MessageCard(Message("Android", "Jetpack Compose"))
        }
    }
}

data class Message(val author: String, val body: String)

@Composable
fun MessageCard(msg: Message) {
    Text(text = msg.author)
    Text(text = msg.body)
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard(
        msg = Message("Colleague", "Hey, take a look at Jetpack Compose, it's great!")
    )
}

  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun MessageCard(msg: Message) {
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}

tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun MessageCard(msg: Message) {
    Row {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
        )
    
       Column {
            Text(text = msg.author)
            Text(text = msg.body)
        }
  
    }
  
}
  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun MessageCard(msg: Message) {
    // Add padding around our message
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
            modifier = Modifier
                // Set image size to 40 dp
                .size(40.dp)
                // Clip image to be shaped as a circle
                .clip(CircleShape)
        )

        // Add a horizontal space between the image and the column
        Spacer(modifier = Modifier.width(8.dp))

        Column {
            Text(text = msg.author)
            // Add a vertical space between the author and message texts
            Spacer(modifier = Modifier.height(4.dp))
            Text(text = msg.body)
        }
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau

Modul 3: Desain material

Compose dibuat untuk mendukung prinsip desain material. Banyak elemen UI-nya mengimplementasikan desain material secara unik. Dalam modul ini, Anda akan menyesuaikan aplikasi dengan widget material.

Menggunakan Desain Material

Desain pesan kita sekarang memiliki tata letak, tetapi belum terlihat bagus.

Jetpack Compose menyediakan implementasi Desain Material dan elemen UI-nya sejak awal. Kita akan meningkatkan tampilan composable MessageCard menggunakan penataan gaya Desain Material.

Dalam hal ini, kita akan menggabungkan fungsi MessageCard dengan tema Material yang dibuat dalam project Anda, ComposeTutorialTheme. Lakukan keduanya di @Preview dan dalam fungsi setContent.

Desain Material di-build berdasarkan tiga pilar: Warna, Tipografi, Bentuk. Mari tambahkan satu per satu

Catatan: Aktivitas Empty Compose menghasilkan tema default untuk project Anda, yang memungkinkan Anda untuk menyesuaikan MaterialTheme. Jika Anda memberi project nama yang berbeda dengan ComposeTutorial, Anda dapat menemukan tema kustom di paket ui.theme.

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeTutorialTheme {
                MessageCard(Message("Android", "Jetpack Compose"))
            }
        }
    }
}

@Preview
@Composable
fun PreviewMessageCard() {
    ComposeTutorialTheme {
        MessageCard(
            msg = Message("Colleague", "Take a look at Jetpack Compose, it's great!")
        )
    }
}

  
tampilkan pratinjau
sembunyikan pratinjau

Warna

Menata gaya dengan warna dari tema gabungan mudah dilakukan, dan Anda dapat menggunakan nilai dari tema tersebut di mana pun warna diperlukan.

Mari kita beri gaya pada judul dan tambahkan bingkai ke gambar:

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)
       )

       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colors.secondaryVariant
           )

           Spacer(modifier = Modifier.height(4.dp))
           Text(text = msg.body)
       }
   }
}

  
tampilkan pratinjau
sembunyikan pratinjau

Tipografi

Gaya Tipografi Material tersedia dalam MaterialTheme, cukup tambahkan ke composable Teks.

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)
       )
       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colors.secondaryVariant,
               style = MaterialTheme.typography.subtitle2
           )

           Spacer(modifier = Modifier.height(4.dp))

           Text(
               text = msg.body,
               style = MaterialTheme.typography.body2
           )
       }
   }
}

  
tampilkan pratinjau
sembunyikan pratinjau

Bentuk

Dengan Bentuk, kita dapat menambahkan sentuhan akhir. Kami juga menambahkan padding ke pesan untuk tata letak yang lebih baik.

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)
       )
       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colors.secondaryVariant,
               style = MaterialTheme.typography.subtitle2
           )

           Spacer(modifier = Modifier.height(4.dp))

           Surface(shape = MaterialTheme.shapes.medium, elevation = 1.dp) {
               Text(
                   text = msg.body,
                   modifier = Modifier.padding(all = 4.dp),
                   style = MaterialTheme.typography.body2
               )
           }
       }
   }
}

  
tampilkan pratinjau
sembunyikan pratinjau

Mengaktifkan tema gelap

Tema gelap (atau mode malam) dapat diaktifkan untuk menghindari tampilan terang, khususnya pada malam hari, atau hanya untuk menghemat baterai perangkat. Berkat dukungan Desain Material, Jetpack Compose dapat menangani tema gelap secara default. Setelah menggunakan warna, teks, dan latar belakang Material akan secara otomatis menyesuaikan dengan latar belakang gelap.

Anda dapat membuat beberapa pratinjau dalam file sebagai fungsi terpisah, atau menambahkan beberapa anotasi ke fungsi yang sama.

Mari kita tambahkan anotasi pratinjau baru dan mengaktifkan mode malam.

@Preview(name = "Light Mode")
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
   ComposeTutorialTheme {
       MessageCard(
           msg = Message("Colleague", "Hey, take a look at Jetpack Compose, it's great!")
       )
   }
}
  
tampilkan pratinjau
sembunyikan pratinjau

Pilihan warna untuk tema terang dan gelap ditentukan dalam file Theme.kt yang dihasilkan IDE.

Sejauh ini, kita telah membuat elemen UI pesan yang menampilkan gambar dan dua teks dengan gaya berbeda, serta terlihat bagus dalam tema terang dan gelap.

@Preview(name = "Light Mode")
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
   ComposeTutorialTheme {
       MessageCard(
           msg = Message("Colleague", "Hey, take a look at Jetpack Compose, it's great!")
       )
   }
}
  
tampilkan pratinjau
sembunyikan pratinjau
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeTutorialTheme {
                MessageCard(Message("Android", "Jetpack Compose"))
            }
        }
    }
}

@Preview
@Composable
fun PreviewMessageCard() {
    ComposeTutorialTheme {
        MessageCard(
            msg = Message("Colleague", "Take a look at Jetpack Compose, it's great!")
        )
    }
}

  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)
       )

       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colors.secondaryVariant
           )

           Spacer(modifier = Modifier.height(4.dp))
           Text(text = msg.body)
       }
   }
}

  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)
       )
       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colors.secondaryVariant,
               style = MaterialTheme.typography.subtitle2
           )

           Spacer(modifier = Modifier.height(4.dp))

           Text(
               text = msg.body,
               style = MaterialTheme.typography.body2
           )
       }
   }
}

  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)
       )
       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colors.secondaryVariant,
               style = MaterialTheme.typography.subtitle2
           )

           Spacer(modifier = Modifier.height(4.dp))

           Surface(shape = MaterialTheme.shapes.medium, elevation = 1.dp) {
               Text(
                   text = msg.body,
                   modifier = Modifier.padding(all = 4.dp),
                   style = MaterialTheme.typography.body2
               )
           }
       }
   }
}

  
tampilkan pratinjau
sembunyikan pratinjau
@Preview(name = "Light Mode")
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
   ComposeTutorialTheme {
       MessageCard(
           msg = Message("Colleague", "Hey, take a look at Jetpack Compose, it's great!")
       )
   }
}
  
tampilkan pratinjau
sembunyikan pratinjau

Modul 4: Daftar dan animasi

Daftar dan animasi ada di mana saja dalam aplikasi. Dalam modul ini, Anda akan mempelajari bagaimana Compose memudahkan pembuatan daftar dan menyenangkan untuk menambahkan animasi.

Membuat daftar pesan

Chat dengan satu pesan terasa agak sepi, jadi mari kita ubah percakapan kita agar memiliki lebih dari satu pesan. Kita perlu membuat fungsi Conversation yang akan menampilkan beberapa pesan. Untuk kasus penggunaan ini, kita dapat menggunakan LazyColumn dan LazyRow. Compose. Composable ini hanya merender elemen yang terlihat di layar, sehingga composable tersebut didesain agar menjadi sangat efisien untuk daftar panjang Google. Pada saat yang sama, keduanya menghindari kompleksitas RecyclerView dengan tata letak XML.

Dalam cuplikan kode ini, Anda dapat melihat bahwa LazyColumn memiliki turunan item. Perlu List sebagai parameter dan lambda-nya menerima parameter yang telah kita beri nama message (kita bisa menamainya apa pun yang kita inginkan) yang merupakan instance Message. Singkatnya, lambda ini dipanggil untuk setiap item dari List yang disediakan: Impor sample set data ini ke dalam project Anda untuk membantu melakukan bootstrap percakapan dengan cepat:

import androidx.compose.foundation.lazy.items

@Composable
fun Conversation(messages: List<Message>) {
    LazyColumn {
        items(messages) { message ->
            MessageCard(message)
        }
    }
}

@Preview
@Composable
fun PreviewConversation() {
    ComposeTutorialTheme {
        Conversation(SampleData.conversationSample)
    }
}

  
tampilkan pratinjau
sembunyikan pratinjau

Menganimasikan pesan saat meluaskan

Percakapan kita menjadi makin menarik. Saatnya berkreasi dengan animasi! Kita akan menambahkan kemampuan untuk meluaskan pesan agar menampilkan pesan yang lebih panjang, yang menganimasikan ukuran konten dan warna latar belakang. Untuk menyimpan status UI lokal ini, kita perlu melacak apakah pesan telah diperpanjang atau tidak. Untuk memantau perubahan status ini, kita harus menggunakan fungsi remember dan mutableStateOf.

Fungsi yang dapat dikomposisi bisa menyimpan status lokal dalam memori menggunakan remember, dan melacak perubahan pada nilai yang diteruskan ke mutableStateOf. Composable (dan turunannya) yang menggunakan status ini akan digambar ulang secara otomatis saat nilai diperbarui. Kami menyebutnya rekomposisi.

Dengan menggunakan API status Compose seperti remember dan mutableStateOf, perubahan apa pun pada status akan otomatis mengupdate UI:

Catatan: Anda harus menambahkan impor berikut untuk menggunakan `by` dengan benar. Alt+Enter akan menambahkannya untuk Anda.

class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           ComposeTutorialTheme {
               Conversation(SampleData.conversationSample)
           }
       }
   }
}

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colors.secondaryVariant, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

        // We keep track if the message is expanded or not in this
        // variable
        var isExpanded by remember { mutableStateOf(false) }

        // We toggle the isExpanded variable when we click on this Column
        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            Text(
                text = msg.author,
                color = MaterialTheme.colors.secondaryVariant,
                style = MaterialTheme.typography.subtitle2
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                elevation = 1.dp,
            ) {
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    // If the message is expanded, we display all its content
                    // otherwise we only display the first line
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.body2
                )
            }
        }
    }
}

  
tampilkan pratinjau
sembunyikan pratinjau

Sekarang kita dapat mengubah latar belakang konten pesan berdasarkan pada isExpanded saat kita mengklik pesan. Kita akan menggunakan pengubah clickable untuk menangani peristiwa klik pada composable. Daripada hanya mengganti warna latar belakang Surface, kita akan menganimasikan warna latar belakang dengan mengubah nilainya secara bertahap dari MaterialTheme.colors.surface ke MaterialTheme.colors.primary, dan sebaliknya. Untuk melakukannya, kita akan menggunakan fungsi animateColorAsState. Terakhir, kita akan menggunakan pengubah animateContentSize untuk menganimasikan ukuran penampung pesan dengan lancar:

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colors.secondaryVariant, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

        // We keep track if the message is expanded or not in this
        // variable
        var isExpanded by remember { mutableStateOf(false) }
        // surfaceColor will be updated gradually from one color to the other
        val surfaceColor: Color by animateColorAsState(
            if (isExpanded) MaterialTheme.colors.primary else MaterialTheme.colors.surface,
        )

        // We toggle the isExpanded variable when we click on this Column
        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            Text(
                text = msg.author,
                color = MaterialTheme.colors.secondaryVariant,
                style = MaterialTheme.typography.subtitle2
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                elevation = 1.dp,
                // surfaceColor color will be changing gradually from primary to surface
                color = surfaceColor,
                // animateContentSize will change the Surface size gradually
                modifier = Modifier.animateContentSize().padding(1.dp)
            ) {
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    // If the message is expanded, we display all its content
                    // otherwise we only display the first line
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.body2
                )
            }
        }
    }
}

  
tampilkan pratinjau
sembunyikan pratinjau
import androidx.compose.foundation.lazy.items

@Composable
fun Conversation(messages: List<Message>) {
    LazyColumn {
        items(messages) { message ->
            MessageCard(message)
        }
    }
}

@Preview
@Composable
fun PreviewConversation() {
    ComposeTutorialTheme {
        Conversation(SampleData.conversationSample)
    }
}

  
tampilkan pratinjau
sembunyikan pratinjau
class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           ComposeTutorialTheme {
               Conversation(SampleData.conversationSample)
           }
       }
   }
}

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colors.secondaryVariant, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

        // We keep track if the message is expanded or not in this
        // variable
        var isExpanded by remember { mutableStateOf(false) }

        // We toggle the isExpanded variable when we click on this Column
        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            Text(
                text = msg.author,
                color = MaterialTheme.colors.secondaryVariant,
                style = MaterialTheme.typography.subtitle2
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                elevation = 1.dp,
            ) {
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    // If the message is expanded, we display all its content
                    // otherwise we only display the first line
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.body2
                )
            }
        }
    }
}

  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colors.secondaryVariant, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

        // We keep track if the message is expanded or not in this
        // variable
        var isExpanded by remember { mutableStateOf(false) }
        // surfaceColor will be updated gradually from one color to the other
        val surfaceColor: Color by animateColorAsState(
            if (isExpanded) MaterialTheme.colors.primary else MaterialTheme.colors.surface,
        )

        // We toggle the isExpanded variable when we click on this Column
        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            Text(
                text = msg.author,
                color = MaterialTheme.colors.secondaryVariant,
                style = MaterialTheme.typography.subtitle2
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                elevation = 1.dp,
                // surfaceColor color will be changing gradually from primary to surface
                color = surfaceColor,
                // animateContentSize will change the Surface size gradually
                modifier = Modifier.animateContentSize().padding(1.dp)
            ) {
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    // If the message is expanded, we display all its content
                    // otherwise we only display the first line
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.body2
                )
            }
        }
    }
}

  
tampilkan pratinjau
sembunyikan pratinjau

Langkah berikutnya

Selamat, Anda telah menyelesaikan tutorial Compose! Anda telah membuat layar chat sederhana yang secara efisien menampilkan daftar pesan yang dapat diperluas & animasi yang berisi gambar dan teks, yang didesain menggunakan prinsip Desain Material dengan menyertakan tema gelap dan pratinjau—semuanya kurang dari 100 baris kode!

Berikut yang telah Anda pelajari sejauh ini:

  • Menentukan fungsi yang dapat dikomposisi
  • Menambahkan berbagai elemen di composable Anda
  • Membuat struktur komponen UI menggunakan composable tata letak
  • Memperluas composable dengan menggunakan pengubah
  • Membuat daftar yang efisien
  • Melacak status dan mengubahnya
  • Menambahkan interaksi pengguna pada composable
  • Menganimasikan pesan saat memperluasnya

Jika Anda ingin lebih mendalami beberapa langkah ini, pelajari referensi di bawah.

Melanjutkan pembelajaran Anda

Penyiapan
Setelah menyelesaikan tutorial Compose, Anda sudah siap untuk mulai mem-build dengan Compose.
Jalur
Lihat jalur codelab dan video pilihan kami yang akan membantu Anda mempelajari dan menguasai Jetpack Compose.