Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.
Tutorial

Dasar-Dasar Jetpack Compose

Jetpack Compose adalah toolkit modern untuk membuat 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 atau langsung membuat widget UI. Sebagai gantinya, Anda akan memanggil fungsi Jetpack Compose untuk memberi tahu elemen apa yang Anda inginkan, selebihnya akan ditangani oleh compiler Compose.

Pratinjau Lengkap
Catatan: Jetpack Compose saat ini dalam versi alfa. Antarmuka API belum selesai, dan akan ada beberapa perubahan.
Pratinjau Lengkap

Pelajaran 1: Fungsi yang dapat dikomposisi

Jetpack Compose dibuat berdasarkan fungsi yang dapat dikomposisi. Fungsi ini memungkinkan Anda menentukan UI aplikasi Anda secara terprogram dengan mendeskripsikan bentuk dan dependensi datanya, bukan berfokus pada proses konstruksi UI. Untuk membuat fungsi yang dapat dikomposisi, cukup tambahkan anotasi @Composable ke nama fungsi.

Menambahkan elemen teks

Untuk memulai, ikuti petunjuk penyiapan Jetpack Compose, dan buat aplikasi menggunakan template Empty Compose Activity. Template default sudah berisi beberapa elemen Compose, tetapi mari kita membuatnya selangkah demi selangkah. Pertama, hapus fungsi "Greeting" dan "Default Preview", lalu hapus blok setContent dari MainActivity, membiarkan aktivitas tetap kosong. Kompilasi dan jalankan aplikasi kosong Anda.

Sekarang tambahkan elemen teks ke aktivitas kosong Anda. Anda dapat melakukannya dengan menentukan blok konten, dan memanggil fungsi Text().

Blok setContent menentukan tata letak aktivitas. Daripada menentukan konten tata letak dengan file XML, panggil fungsi yang dapat dikomposisi. Jetpack Compose menggunakan plugin compiler Kotlin kustom untuk mengubah fungsi yang dapat dikomposisi ini menjadi elemen UI aplikasi. Misalnya, fungsi Text() ditentukan dengan library Compose UI; panggil fungsi tersebut untuk mendeklarasikan elemen teks di aplikasi Anda.

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

Menentukan fungsi yang dapat dikomposisi

Fungsi yang dapat dikomposisi hanya bisa dipanggil dari dalam cakupan fungsi yang dapat dikomposisi lainnya. Untuk membuat fungsi yang dapat dikomposisi, tambahkan anotasi @Composable. Untuk mencoba ini, tentukan fungsi Greeting() yang mendapatkan nama dan menggunakan nama tersebut untuk mengonfigurasi elemen teks.

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

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

Melihat pratinjau fungsi di Android Studio

Build canary Android Studio saat ini memungkinkan Anda melihat pratinjau fungsi yang dapat dikomposisi yang berada di dalam IDE, sehingga Anda tidak perlu mendownload aplikasi di perangkat Android atau emulator. Batasan utamanya adalah, fungsi yang dapat dikomposisi tidak boleh mengambil parameter apa pun. Karena alasan ini, Anda tidak dapat melihat pratinjau fungsi Greeting() secara langsung. Sebagai gantinya, buat fungsi kedua bernama PreviewGreeting(), yang memanggil Greeting() dengan parameter yang sesuai. Tambahkan anotasi @Preview sebelum @Composable.

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

@Preview
@Composable
fun PreviewGreeting() {
    Greeting("Android")
}
  
tampilkan pratinjau
sembunyikan pratinjau

Membuat ulang project Anda. Aplikasi itu sendiri tidak berubah, karena fungsi previewGreeting() 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 refresh di bagian atas jendela pratinjau.

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

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

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

Pelajaran 2: Tata Letak

Elemen UI bersifat hierarkis, dengan elemen yang terdapat dalam elemen lainnya. Di Compose, Anda membuat hierarki UI dengan memanggil fungsi yang dapat dikomposisi dari fungsi yang dapat dikomposisi lainnya.

Memulai dengan Text

Kembali ke aktivitas Anda, lalu ganti fungsi Greeting() dengan fungsi NewsStory() baru. Selama sisa tutorial, Anda akan mengubah fungsi NewsStory() itu, dan tidak akan menggunakan kode Activity lagi.

Membuat fungsi pratinjau terpisah yang tidak dipanggil oleh aplikasi merupakan praktik terbaik; memiliki fungsi pratinjau khusus akan meningkatkan performa, dan juga memudahkan penyiapan beberapa pratinjau nantinya. Jadi, buat fungsi pratinjau default yang hanya memanggil fungsi NewsStory(). Saat Anda membuat perubahan pada NewsStory() selama tutorial ini, pratinjau mencerminkan perubahan tersebut.

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

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NewsStory()
        }
    }
}

@Composable
fun NewsStory() {
    Text("A day in Shark Fin Cove")
    Text("Davenport, California")
    Text("December 2018")
}

@Preview
@Composable
fun DefaultPreview() {
    NewsStory()
}
  
tampilkan pratinjau
sembunyikan pratinjau

Menggunakan Column

Fungsi Column memungkinkan Anda menumpuk elemen secara vertikal. Tambahkan Column ke fungsi NewsStory().

Setelan default menumpuk semua turunan secara langsung, satu per satu, tanpa spasi. Kolom itu sendiri ditempatkan di sudut kiri atas tampilan konten.

@Composable
fun NewsStory() {
    Column {
        Text("A day in Shark Fin Cove")
        Text("Davenport, California")
        Text("December 2018")
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau

Menambahkan setelan gaya ke kolom

Dengan meneruskan parameter ke panggilan Column, Anda dapat mengonfigurasi ukuran dan posisi kolom, serta cara turunan kolom diatur.

Setelan tersebut memiliki arti berikut:

  • modifier: Memungkinkan Anda mengonfigurasi tata letak. Dalam hal ini, terapkan pengubah Modifier.padding, yang menyisipkan kolom dari tampilan di sekitarnya.
@Composable
fun NewsStory() {
    Column(
        modifier = Modifier.padding(16.dp)
    ) {
        Text("A day in Shark Fin Cove")
        Text("Davenport, California")
        Text("December 2018")
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau

Menambahkan gambar

Kita ingin menambahkan grafis di atas teks. Gunakan Resource Manager untuk menambahkan foto ini ke resource drawable aplikasi Anda, dengan nama header.

Sekarang ubah fungsi NewsStory() Anda. Anda akan menambahkan panggilan ke Image() untuk menempatkan grafis di Column. Gambar tidak akan disesuaikan dengan benar, tetapi itu bukan masalah - Anda dapat memperbaikinya di langkah berikutnya.

@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)

    Column(
        modifier = Modifier.padding(16.dp)
    ) {
        Image(image)

        Text("A day in Shark Fin Cove")
        Text("Davenport, California")
        Text("December 2018")
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau

Grafis ditambahkan ke tata letak Anda, tetapi belum berukuran yang tepat. Untuk mengatur gaya gambar, teruskan Modifier ukuran ke panggilan ke Image().

  • preferredHeightIn(maxHeight = 180.dp): Menentukan tinggi maksimum gambar.
  • fillMaxWidth(): Menentukan bahwa gambar harus cukup lebar untuk mengisi tata letak.

Anda juga perlu meneruskan parameter contentScale ke Image():

  • contentScale = ContentScale.Crop: Menentukan bahwa grafis harus memenuhi lebar kolom, dan akan di-crop agar tingginya sesuai jika perlu.
@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)
    Column(
        modifier = Modifier.padding(16.dp)
    ) {
        val imageModifier = Modifier
            .preferredHeightIn(maxHeight = 180.dp)
            .fillMaxWidth()

        Image(image, modifier = imageModifier,
                  contentScale = ContentScale.Crop)

        Text("A day in Shark Fin Cove")
        Text("Davenport, California")
        Text("December 2018")
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau

Tambahkan Spacer untuk memisahkan grafis dari heading.

@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)
    Column(
        modifier = Modifier.padding(16.dp)
    ) {
        val imageModifier = Modifier
            .preferredHeightIn(maxHeight = 180.dp)
            .fillMaxWidth()

        Image(image, modifier = imageModifier,
                  contentScale = ContentScale.Crop)
        Spacer(Modifier.preferredHeight(16.dp))

        Text("A day in Shark Fin Cove")
        Text("Davenport, California")
        Text("December 2018")
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NewsStory()
        }
    }
}

@Composable
fun NewsStory() {
    Text("A day in Shark Fin Cove")
    Text("Davenport, California")
    Text("December 2018")
}

@Preview
@Composable
fun DefaultPreview() {
    NewsStory()
}
  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun NewsStory() {
    Column {
        Text("A day in Shark Fin Cove")
        Text("Davenport, California")
        Text("December 2018")
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun NewsStory() {
    Column(
        modifier = Modifier.padding(16.dp)
    ) {
        Text("A day in Shark Fin Cove")
        Text("Davenport, California")
        Text("December 2018")
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)

    Column(
        modifier = Modifier.padding(16.dp)
    ) {
        Image(image)

        Text("A day in Shark Fin Cove")
        Text("Davenport, California")
        Text("December 2018")
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)
    Column(
        modifier = Modifier.padding(16.dp)
    ) {
        val imageModifier = Modifier
            .preferredHeightIn(maxHeight = 180.dp)
            .fillMaxWidth()

        Image(image, modifier = imageModifier,
                  contentScale = ContentScale.Crop)

        Text("A day in Shark Fin Cove")
        Text("Davenport, California")
        Text("December 2018")
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)
    Column(
        modifier = Modifier.padding(16.dp)
    ) {
        val imageModifier = Modifier
            .preferredHeightIn(maxHeight = 180.dp)
            .fillMaxWidth()

        Image(image, modifier = imageModifier,
                  contentScale = ContentScale.Crop)
        Spacer(Modifier.preferredHeight(16.dp))

        Text("A day in Shark Fin Cove")
        Text("Davenport, California")
        Text("December 2018")
    }
}
  
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 material.

Menerapkan bentuk

Salah satu pilar Sistem Desain Material adalah Shape. Gunakan fungsi clip() untuk membundarkan sudut gambar.

Shape tidak terlihat, tetapi grafis di-crop agar pas dengan Shape, sehingga grafis memiliki sudut yang sedikit membundar sekarang.

@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)
    Column(
        modifier = Modifier.padding(16.dp)
    ) {
        val imageModifier = Modifier
            .preferredHeightIn(maxHeight = 180.dp)
            .fillMaxWidth()
            .clip(shape = RoundedCornerShape(4.dp))

        Image(image, modifier = imageModifier,
                  contentScale = ContentScale.Crop)
        Spacer(Modifier.preferredHeight(16.dp))

        Text("A day in Shark Fin Cove")
        Text("Davenport, California")
        Text("December 2018")
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau

Memberi gaya pada teks

Compose memudahkan pemanfaatan prinsip Desain Material. Terapkan MaterialTheme ke komponen yang sudah Anda buat.

@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)
    MaterialTheme {
        Column(
            modifier = Modifier.padding(16.dp)
        ) {
            val imageModifier = Modifier
                .preferredHeightIn(maxHeight = 180.dp)
                .fillMaxWidth()
                .clip(shape = RoundedCornerShape(4.dp))

            Image(image, modifier = imageModifier,
                      contentScale = ContentScale.Crop)
            Spacer(Modifier.preferredHeight(16.dp))

            Text("A day in Shark Fin Cove")
            Text("Davenport, California")
            Text("December 2018")
        }
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau

Perubahannya tidak begitu terlihat, tetapi teks sekarang menggunakan gaya teks default MaterialTheme. Selanjutnya, terapkan gaya paragraf tertentu ke setiap elemen teks.

@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)
    MaterialTheme {
        val typography = MaterialTheme.typography
        Column(
            modifier = Modifier.padding(16.dp)
        ) {
            val imageModifier = Modifier
                .preferredHeightIn(maxHeight = 180.dp)
                .fillMaxWidth()
                .clip(shape = RoundedCornerShape(4.dp))

            Image(image, modifier = imageModifier,
                      contentScale = ContentScale.Crop)
            Spacer(Modifier.preferredHeight(16.dp))

            Text("A day in Shark Fin Cove",
                style = typography.h6)
            Text("Davenport, California",
                style = typography.body2)
            Text("December 2018",
                style = typography.body2)
        }
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau

Dalam hal ini, judul artikelnya cukup singkat. Namun, terkadang artikel memiliki judul yang panjang, dan kita tidak ingin judul yang panjang membuat tampilan aplikasi menjadi kurang apik. Coba ubah elemen teks pertama.

@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)
    MaterialTheme {
        val typography = MaterialTheme.typography
        Column(
            modifier = Modifier.padding(16.dp)
        ) {
            val imageModifier = Modifier
                .preferredHeightIn(maxHeight = 180.dp)
                .fillMaxWidth()
                .clip(shape = RoundedCornerShape(4.dp))

            Image(image, modifier = imageModifier,
                      contentScale = ContentScale.Crop)
            Spacer(Modifier.preferredHeight(16.dp))

            Text(
                "A day wandering through the sandhills " +
                     "in Shark Fin Cove, and a few of the " +
                     "sights I saw",
                style = typography.h6)
            Text("Davenport, California",
                style = typography.body2)
            Text("December 2018",
                style = typography.body2)
        }
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau

Konfigurasikan elemen teks untuk menetapkan panjang maksimum 2 baris. Setelan tidak berpengaruh jika panjang teks tidak melebihi batasan itu, tetapi teks yang ditampilkan otomatis dipotong jika terlalu panjang.

@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)
    MaterialTheme {
        val typography = MaterialTheme.typography
        Column(
            modifier = Modifier.padding(16.dp)
        ) {
            val imageModifier = Modifier
                .preferredHeightIn(maxHeight = 180.dp)
                .fillMaxWidth()
                .clip(shape = RoundedCornerShape(4.dp))

            Image(image, modifier = imageModifier,
                      contentScale = ContentScale.Crop)
            Spacer(Modifier.preferredHeight(16.dp))

            Text(
                "A day wandering through the sandhills " +
                     "in Shark Fin Cove, and a few of the " +
                     "sights I saw",
                style = typography.h6,
                maxLines = 2,
                overflow = TextOverflow.Ellipsis)
            Text("Davenport, California",
                style = typography.body2)
            Text("December 2018",
                style = typography.body2)
        }
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)
    Column(
        modifier = Modifier.padding(16.dp)
    ) {
        val imageModifier = Modifier
            .preferredHeightIn(maxHeight = 180.dp)
            .fillMaxWidth()
            .clip(shape = RoundedCornerShape(4.dp))

        Image(image, modifier = imageModifier,
                  contentScale = ContentScale.Crop)
        Spacer(Modifier.preferredHeight(16.dp))

        Text("A day in Shark Fin Cove")
        Text("Davenport, California")
        Text("December 2018")
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)
    MaterialTheme {
        Column(
            modifier = Modifier.padding(16.dp)
        ) {
            val imageModifier = Modifier
                .preferredHeightIn(maxHeight = 180.dp)
                .fillMaxWidth()
                .clip(shape = RoundedCornerShape(4.dp))

            Image(image, modifier = imageModifier,
                      contentScale = ContentScale.Crop)
            Spacer(Modifier.preferredHeight(16.dp))

            Text("A day in Shark Fin Cove")
            Text("Davenport, California")
            Text("December 2018")
        }
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)
    MaterialTheme {
        val typography = MaterialTheme.typography
        Column(
            modifier = Modifier.padding(16.dp)
        ) {
            val imageModifier = Modifier
                .preferredHeightIn(maxHeight = 180.dp)
                .fillMaxWidth()
                .clip(shape = RoundedCornerShape(4.dp))

            Image(image, modifier = imageModifier,
                      contentScale = ContentScale.Crop)
            Spacer(Modifier.preferredHeight(16.dp))

            Text("A day in Shark Fin Cove",
                style = typography.h6)
            Text("Davenport, California",
                style = typography.body2)
            Text("December 2018",
                style = typography.body2)
        }
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)
    MaterialTheme {
        val typography = MaterialTheme.typography
        Column(
            modifier = Modifier.padding(16.dp)
        ) {
            val imageModifier = Modifier
                .preferredHeightIn(maxHeight = 180.dp)
                .fillMaxWidth()
                .clip(shape = RoundedCornerShape(4.dp))

            Image(image, modifier = imageModifier,
                      contentScale = ContentScale.Crop)
            Spacer(Modifier.preferredHeight(16.dp))

            Text(
                "A day wandering through the sandhills " +
                     "in Shark Fin Cove, and a few of the " +
                     "sights I saw",
                style = typography.h6)
            Text("Davenport, California",
                style = typography.body2)
            Text("December 2018",
                style = typography.body2)
        }
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau
@Composable
fun NewsStory() {
    val image = imageResource(R.drawable.header)
    MaterialTheme {
        val typography = MaterialTheme.typography
        Column(
            modifier = Modifier.padding(16.dp)
        ) {
            val imageModifier = Modifier
                .preferredHeightIn(maxHeight = 180.dp)
                .fillMaxWidth()
                .clip(shape = RoundedCornerShape(4.dp))

            Image(image, modifier = imageModifier,
                      contentScale = ContentScale.Crop)
            Spacer(Modifier.preferredHeight(16.dp))

            Text(
                "A day wandering through the sandhills " +
                     "in Shark Fin Cove, and a few of the " +
                     "sights I saw",
                style = typography.h6,
                maxLines = 2,
                overflow = TextOverflow.Ellipsis)
            Text("Davenport, California",
                style = typography.body2)
            Text("December 2018",
                style = typography.body2)
        }
    }
}
  
tampilkan pratinjau
sembunyikan pratinjau

Selesai

Bagus sekali! Anda telah mempelajari dasar-dasar Compose.

Yang telah Anda pelajari:

  • Menentukan fungsi yang dapat disusun
  • Menggunakan dan menata gaya kolom untuk menyempurnakan tata letak
  • Menata gaya aplikasi Anda dengan prinsip Desain Material

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

Lanjutkan pembelajaran Anda

Jalur

Lihat jalur codelab dan video pilihan kami yang akan membantu Anda mempelajari dan menguasai Jetpack Compose.

Panduan

Dalami dokumen yang ada untuk mempelajari lebih lanjut tentang API Jetpack Compose yang direferensikan dalam tutorial ini.

Contoh

Dapatkan inspirasi dengan aplikasi contoh ini, yang menunjukkan cara menggunakan fitur Compose yang canggih.