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 composable untuk menentukan elemen yang diinginkan, 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, lalu buat aplikasi dengan memilih New Project dan di bagian kategori Phone and Tablet, pilih Empty Compose Activity. Beri nama aplikasi ComposeTutorial lalu klik Finish. Template default sudah berisi beberapa elemen Compose, tetapi dalam tutorial ini Anda akan mem-build elemen langkah demi langkah.

Pertama, tampilkan teks “Halo dunia!” dengan menambahkan elemen teks di dalam metode onCreate. Anda dapat melakukannya dengan menentukan blok konten, dan memanggil fungsi composable Text. Blok setContent menentukan tata letak aktivitas tempat fungsi composable dipanggil. Fungsi composable hanya dapat dipanggil dari fungsi composable lain.

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

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.Text

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

Menentukan fungsi composable

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.

// ...
import androidx.compose.runtime.Composable

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 di Android Studio

Anotasi @Preview memungkinkan Anda melihat pratinjau fungsi composable dalam Android Studio tanpa harus mem-build dan menginstal aplikasi ke perangkat Android atau emulator. Anotasi ini harus digunakan pada fungsi composable yang tidak menggunakan parameter. Karena alasan ini, Anda tidak dapat melihat pratinjau fungsi MessageCard secara langsung. Sebagai gantinya, buat fungsi kedua bernama PreviewMessageCard, yang memanggil MessageCard dengan parameter yang sesuai. Tambahkan anotasi @Preview sebelum @Composable.

// ...
import androidx.compose.ui.tooling.preview.Preview

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

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

Membuat ulang project Anda. Aplikasi itu sendiri tidak berubah, karena fungsi PreviewMessageCard baru tidak dipanggil di mana pun, tetapi Android Studio menambahkan jendela pratinjau yang dapat Anda luaskan dengan mengklik tampilan (desain/kode) terpisah. Jendela ini menampilkan pratinjau elemen UI yang dibuat oleh fungsi composable yang ditandai dengan anotasi @Preview. Untuk memperbarui pratinjau kapan pun, klik tombol muat ulang di bagian atas jendela pratinjau.

Pratinjau fungsi composable di Android Studio
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.Text

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

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
// ...
import androidx.compose.ui.tooling.preview.Preview

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

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}
  
tampilkan pratinjau
sembunyikan pratinjau
Pratinjau fungsi composable di Android Studio

Tutorial 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 composable dari fungsi composable lainnya.

Menambahkan beberapa teks

Sejauh ini, Anda telah mem-build fungsi composable dan pratinjau pertama. Untuk menemukan kemampuan Jetpack Compose lainnya, Anda akan mem-build layar pesan sederhana yang berisi daftar pesan yang dapat diperluas dengan beberapa animasi.

Mulailah dengan melengkapi composable pesan, dengan menampilkan nama penulis dan konten pesannya. Anda harus mengubah parameter composable terlebih dahulu untuk menerima objek Message sebagai ganti String, dan menambahkan composable Text lain di dalam composable MessageCard. Pastikan Anda juga memperbarui 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 lain, sehingga membuat teks tidak dapat dibaca.

Menggunakan Kolom

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

// ...
import androidx.compose.foundation.layout.Column

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

tampilkan pratinjau
sembunyikan pratinjau

Menambahkan elemen gambar

Lengkapi kartu pesan Anda dengan menambahkan foto profil pengirim. Gunakan Resource Manager 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.

// ...
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Row
import androidx.compose.ui.res.painterResource

@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 Anda memiliki struktur yang tepat, tetapi elemennya tidak diberi spasi dengan baik dan gambarnya terlalu besar. Untuk mendekorasi atau mengonfigurasi composable, 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 lengkap. Anda akan menggunakan beberapa di antaranya untuk membuat tata letak lebih baik.

// ...
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp

@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
Pratinjau dua composable Teks yang tumpang-tindih
// ...
import androidx.compose.foundation.layout.Column

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

tampilkan pratinjau
sembunyikan pratinjau
// ...
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Row
import androidx.compose.ui.res.painterResource

@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
// ...
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp

@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

Pelajaran 3: Desain Material

Compose dibuat untuk mendukung prinsip Desain Material. Banyak elemen UI-nya mengimplementasikan Desain Material secara unik. Dalam pelajaran ini, Anda akan menyesuaikan aplikasi dengan widget Desain Material.

Menggunakan Desain Material

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

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

Untuk memulai, gabungkan fungsi MessageCard dengan tema Material yang dibuat di project Anda, ComposeTutorialTheme, serta Surface. Lakukan keduanya di @Preview dan dalam fungsi setContent. Dengan melakukannya, composable dapat mewarisi gaya seperti yang ditentukan dalam tema aplikasi untuk memastikan konsistensi di seluruh aplikasi.

Desain Material di-build berdasarkan tiga pilar: Color, Typography, dan Shape. Anda akan menambahkannya satu per satu.

Catatan: Template Empty Compose Activity menghasilkan tema default untuk project Anda, yang memungkinkan Anda menyesuaikan MaterialTheme. Jika Anda memberi project nama yang berbeda dengan ComposeTutorial, Anda dapat menemukan tema kustom di file Theme.kt dalam sub-paket ui.theme.

// ...

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

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

  
tampilkan pratinjau
sembunyikan pratinjau

Warna

Gunakan MaterialTheme.colors untuk memberi gaya dengan warna dari tema gabungan. Anda dapat menggunakan nilai-nilai ini dari tema di mana pun warna diperlukan.

Beri gaya pada judul dan tambahkan bingkai ke gambar.

// ...
import androidx.compose.foundation.border
import androidx.compose.material.MaterialTheme

@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 Text.

// ...

@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 Shape, Anda dapat menambahkan sentuhan akhir. Pertama, gabungkan teks isi pesan di sekitar composable Surface. Dengan melakukannya, Anda dapat menyesuaikan bentuk dan ketinggian isi pesan. Padding juga ditambahkan ke pesan untuk tata letak yang lebih baik.

// ...
import androidx.compose.material.Surface

@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 Desain Material, teks dan latar belakang akan otomatis menyesuaikan dengan latar belakang gelap.

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

Menambahkan anotasi pratinjau baru dan mengaktifkan mode malam.

// ...
import android.content.res.Configuration

@Preview(name = "Light Mode")
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
   ComposeTutorialTheme {
    Surface {
      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, Anda telah membuat elemen UI pesan yang menampilkan gambar dan dua teks dengan gaya berbeda, serta terlihat bagus dalam tema terang dan gelap.

// ...
import android.content.res.Configuration

@Preview(name = "Light Mode")
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
   ComposeTutorialTheme {
    Surface {
      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 {
                Surface(modifier = Modifier.fillMaxSize()) {
                    MessageCard(Message("Android", "Jetpack Compose"))
                }
            }
        }
    }
}

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

  
tampilkan pratinjau
sembunyikan pratinjau
// ...
import androidx.compose.foundation.border
import androidx.compose.material.MaterialTheme

@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
// ...
import androidx.compose.material.Surface

@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
// ...
import android.content.res.Configuration

@Preview(name = "Light Mode")
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
   ComposeTutorialTheme {
    Surface {
      MessageCard(
        msg = Message("Colleague", "Hey, take a look at Jetpack Compose, it's great!")
      )
    }
   }
}
  
tampilkan pratinjau
sembunyikan pratinjau
Gambar 3. Pratinjau yang menampilkan composable bertema terang dan gelap.

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 ubah percakapan Anda agar memiliki lebih dari satu pesan. Anda harus membuat fungsi Conversation yang akan menampilkan beberapa pesan. Untuk kasus penggunaan ini, gunakan LazyColumn dan LazyRow Compose. Composable ini hanya merender elemen yang terlihat di layar, sehingga composable tersebut didesain agar menjadi sangat efisien untuk daftar yang panjang.

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

// ...
import androidx.compose.foundation.lazy.LazyColumn
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 menjadi lebih menarik. Saatnya berkreasi dengan animasi! Anda 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, Anda perlu memantau apakah pesan telah diluaskan atau tidak. Untuk memantau perubahan status ini, Anda harus menggunakan fungsi remember dan mutableStateOf.

Fungsi composable dapat menyimpan status lokal dalam memori menggunakan remember, dan memantau perubahan pada nilai yang diteruskan ke mutableStateOf. Composable (dan turunannya) yang menggunakan status ini akan digambar ulang secara otomatis saat nilai diperbarui. Ini disebut rekomposisi.

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

Catatan: Anda harus menambahkan impor berikut untuk menggunakan by dengan benar. Alt+Enter atau Option+Enter akan menambahkannya untuk Anda.
import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue

// ...
import androidx.compose.foundation.clickable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue

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

// ...
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.animateContentSize

@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 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.LazyColumn
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
// ...
import androidx.compose.foundation.clickable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue

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
// ...
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.animateContentSize

@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 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.

Langkah berikutnya

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.