Menambahkan daftar yang dapat di-scroll

1. Sebelum memulai

Dalam codelab ini, Anda akan mempelajari cara membuat daftar yang dapat di-scroll di aplikasi menggunakan Jetpack Compose.

Anda akan mengerjakan aplikasi Affirmations, yang menampilkan daftar afirmasi yang dipasangkan dengan gambar indah untuk membawa hal positif ke hari Anda.

Data sudah ada, Anda hanya perlu mengambil data tersebut dan menampilkannya di UI.

Prasyarat

  • Pemahaman tentang daftar di Kotlin
  • Pengalaman membuat tata letak dengan Jetpack Compose
  • Pengalaman menjalankan aplikasi di perangkat atau emulator

Yang akan Anda pelajari

  • Cara membuat kartu Desain Material menggunakan Jetpack Compose
  • Cara membuat daftar yang dapat di-scroll menggunakan Jetpack Compose

Yang akan Anda bangun

  • Anda akan mengambil aplikasi yang sudah ada dan menambahkan daftar yang dapat di-scroll ke UI

Produk jadi akan terlihat seperti ini:

286f5132aa155fa6.png

Yang akan Anda butuhkan

  • Komputer dengan akses internet, browser web, dan Android Studio
  • Akses ke GitHub

Mendownload kode awal

Di Android Studio, buka folder basic-android-kotlin-compose-training-affirmations.

Aplikasi diharapkan menampilkan layar kosong saat dibangun dari kode cabang starter.

3beea0789e2eeaba.png

2. Membuat class data item daftar

Membuat class data untuk Affirmation

Di aplikasi Android, daftar terdiri dari item daftar. Untuk data tunggal, ini bisa berupa hal sederhana seperti string atau bilangan bulat. Untuk item daftar yang memiliki beberapa data, seperti gambar dan teks, Anda memerlukan class yang berisi semua properti ini. Class data adalah jenis class yang hanya berisi properti. Class tersebut dapat menyediakan beberapa metode utilitas agar berfungsi dengan properti tersebut.

  1. Buat paket baru di bagian com.example.affirmations.

89c8d8485c685fac.png

Beri nama paket baru tersebut dengan model. Paket model akan berisi model data yang akan direpresentasikan oleh class data. Class data akan terdiri dari properti yang mewakili informasi yang relevan dengan yang akan disebut "Affirmation", yang akan terdiri dari resource string dan resource gambar. Paket adalah direktori yang berisi beberapa class dan bahkan direktori lainnya.

b54fb6bf57de44c8.png

  1. Buat class baru di paket com.example.affirmations.model.

58510a651bd49100.png

Beri nama class baru tersebut dengan Affirmation dan jadikan Data class.

7f94b65ee3d8407f.png

  1. Setiap Affirmation terdiri dari satu gambar dan satu string. Buat dua properti val di class data Affirmation. Salah satunya harus disebut stringResourceId dan yang lainnya imageResourceId. Keduanya harus berupa bilangan bulat.

Affirmation.kt

data class Affirmation(
    val stringResourceId: Int,
    val imageResourceId: Int
)
  1. Anotasikan properti stringResourceId dengan anotasi @StringRes dan anotasikan imageResourceId dengan anotasi @DrawableRes. stringResourceId mewakili ID untuk teks afirmasi yang disimpan di resource string. imageResourceId mewakili ID untuk gambar afirmasi yang disimpan di resource drawable.

Affirmation.kt

import androidx.annotation.DrawableRes
import androidx.annotation.StringRes

data class Affirmation(
    @StringRes val stringResourceId: Int,
    @DrawableRes val imageResourceId: Int
)
  1. Dalam paket com.example.affirmations.data, buka file Datasource.kt dan hapus tanda komentar pada dua pernyataan impor serta konten class Datasource.

Datasource.kt

import com.example.affirmations.R
import com.example.affirmations.model.Affirmation

class Datasource() {
    fun loadAffirmations(): List<Affirmation> {
        return listOf<Affirmation>(
            Affirmation(R.string.affirmation1, R.drawable.image1),
            Affirmation(R.string.affirmation2, R.drawable.image2),
            Affirmation(R.string.affirmation3, R.drawable.image3),
            Affirmation(R.string.affirmation4, R.drawable.image4),
            Affirmation(R.string.affirmation5, R.drawable.image5),
            Affirmation(R.string.affirmation6, R.drawable.image6),
            Affirmation(R.string.affirmation7, R.drawable.image7),
            Affirmation(R.string.affirmation8, R.drawable.image8),
            Affirmation(R.string.affirmation9, R.drawable.image9),
            Affirmation(R.string.affirmation10, R.drawable.image10))
    }
}

3. Menambahkan daftar ke aplikasi

Membuat kartu item daftar

Aplikasi ini dimaksudkan untuk menampilkan daftar afirmasi. Langkah pertama dalam mengonfigurasi UI untuk menampilkan daftar adalah membuat item daftar. Setiap item afirmasi terdiri dari gambar dan string. Data untuk setiap item ini dilengkapi dengan kode awal, dan Anda akan membuat komponen UI untuk menampilkan item tersebut.

Item akan terdiri dari composable Card, yang berisi Image dan composable Text. Di Compose, Card adalah platform yang menampilkan konten dan tindakan dalam satu penampung. Kartu Affirmation akan terlihat seperti ini di pratinjau:

4f657540712a069f.png

Kartu ini menampilkan gambar dengan teks di bawahnya. Tata letak vertikal ini dapat dibuat menggunakan composable Column yang digabungkan dalam composable Card. Anda dapat mencobanya sendiri, atau ikuti langkah-langkah di bawah untuk melakukannya.

  1. Buka file MainActivity.kt.
  2. Buat metode baru di bawah metode AffirmationsApp(), yang disebut AffirmationCard(), dan anotasikan dengan anotasi @Composable.

MainActivity.kt

@Composable
fun AffirmationsApp() {
}

@Composable
fun AffirmationCard() {

}
  1. Edit tanda tangan metode untuk mengambil objek Affirmation sebagai parameter. Objek Affirmation berasal dari paket model.

MainActivity.kt

import com.example.affirmations.model.Affirmation

@Composable
fun AffirmationCard(affirmation: Affirmation) {

}
  1. Tambahkan parameter modifier ke tanda tangan. Setel nilai default Modifier untuk parameter.

MainActivity.kt

@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {

}
  1. Di dalam metode AffirmationCard, panggil composable Card. Teruskan parameter modifier.

MainActivity.kt

import androidx.compose.material3.Card

@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
    Card(modifier = modifier) {

    }
}
  1. Tambahkan composable Column di dalam composable Card. Item dalam composable Column menyusun dirinya sendiri secara vertikal di UI. Hal ini memungkinkan Anda menempatkan gambar di atas teks terkait. Sebaliknya, composable Row mengatur item yang ditampung secara horizontal.

MainActivity.kt

import androidx.compose.foundation.layout.Column

@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
    Card(modifier = modifier) {
        Column {

        }
    }

}
  1. Tambahkan composable Image di dalam isi lambda dari composable Column. Ingat kembali bahwa composable Image selalu memerlukan resource untuk ditampilkan, dan contentDescription. Resource ini harus berupa painterResource yang diteruskan ke parameter painter. Metode painterResource akan memuat vektor drawable atau format aset raster seperti PNG. Selain itu, teruskan stringResource untuk parameter contentDescription.

MainActivity.kt

import androidx.compose.foundation.Image
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource

@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
    Card(modifier = modifier) {
        Column {
            Image(
                painter = painterResource(affirmation.imageResourceId),
                contentDescription = stringResource(affirmation.stringResourceId),
            )
        }
    }
}
  1. Selain parameter painter dan contentDescription, teruskan modifier dan contentScale. contentScale menentukan cara gambar harus diskalakan dan ditampilkan. Objek Modifier harus memiliki atribut fillMaxWidth yang disetel dan tinggi 194.dp. contentScale harus ContentScale.Crop.

MainActivity.kt

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.ui.unit.dp
import androidx.compose.ui.layout.ContentScale

@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
    Card(modifier = modifier) {
        Column {
            Image(
                painter = painterResource(affirmation.imageResourceId),
                contentDescription = stringResource(affirmation.stringResourceId),
                modifier = Modifier
                    .fillMaxWidth()
                    .height(194.dp),
                contentScale = ContentScale.Crop
            )
        }
    }
}
  1. Di dalam Column, buat composable Text setelah composable Image. Teruskan stringResource dari affirmation.stringResourceId ke parameter text, teruskan objek Modifier dengan atribut padding yang disetel ke 16.dp, dan setel tema teks dengan meneruskan MaterialTheme.typography.headlineSmall ke parameter style.

MainActivity.kt

import androidx.compose.material3.Text
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.platform.LocalContext

@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
    Card(modifier = modifier) {
        Column {
            Image(
                painter = painterResource(affirmation.imageResourceId),
                contentDescription = stringResource(affirmation.stringResourceId),
                modifier = Modifier
                    .fillMaxWidth()
                    .height(194.dp),
                contentScale = ContentScale.Crop
            )
            Text(
                text = LocalContext.current.getString(affirmation.stringResourceId),
                modifier = Modifier.padding(16.dp),
                style = MaterialTheme.typography.headlineSmall
            )
        }
    }
}

Pratinjau composable AffirmationCard

Kartu ini adalah inti dari UI untuk aplikasi Affirmations, dan Anda telah bekerja keras untuk membuatnya. Untuk memeriksa apakah kartu sudah benar, Anda dapat membuat composable yang dapat dilihat pratinjaunya tanpa meluncurkan seluruh aplikasi.

  1. Buat metode pribadi bernama AffirmationCardPreview(). Anotasikan metode dengan @Preview dan @Composable.

MainActivity.kt

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

@Preview
@Composable
private fun AffirmationCardPreview() {

}
  1. Di dalam metode, panggil composable AffirmationCard, dan teruskan objek Affirmation baru dengan resource string R.string.affirmation1 dan resource drawable R.drawable.image1 yang diteruskan ke konstruktornya.

MainActivity.kt

@Preview
@Composable
private fun AffirmationCardPreview() {
    AffirmationCard(Affirmation(R.string.affirmation1, R.drawable.image1))
}
  1. Buka tab Split dan Anda akan melihat pratinjau AffirmationCard. Jika perlu, klik Build & Refresh di panel Design untuk menampilkan pratinjau.

924a4df2c1db236c.png

Membuat daftar

Komponen item daftar adalah elemen penyusun daftar. Setelah item daftar dibuat, Anda dapat memanfaatkannya untuk membuat komponen daftar itu sendiri.

  1. Buat fungsi yang disebut AffirmationList(), anotasikan dengan anotasi @Composable, dan deklarasikan List objek Affirmation sebagai parameter di tanda tangan metode.

MainActivity.kt

@Composable
fun AffirmationList(affirmationList: List<Affirmation>) {

}
  1. Deklarasikan objek modifier sebagai parameter dalam tanda tangan metode dengan nilai default Modifier.

MainActivity.kt

@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {

}
  1. Di Jetpack Compose, daftar yang dapat di-scroll dapat dibuat menggunakan composable LazyColumn. Perbedaan antara LazyColumn dan Column adalah bahwa Column harus digunakan saat Anda memiliki sedikit item untuk ditampilkan, karena Compose memuat semuanya sekaligus. Column hanya dapat menyimpan composable dengan jumlah yang tetap atau telah ditentukan. LazyColumn dapat menambahkan konten sesuai keperluan, yang menjadikannya cocok untuk daftar panjang, terutama jika panjang daftar tidak diketahui. LazyColumn juga menyediakan scroll secara default, tanpa kode tambahan. Deklarasikan composable LazyColumn di dalam fungsi AffirmationList(). Teruskan objek modifier sebagai argumen ke LazyColumn.

MainActivity.kt

import androidx.compose.foundation.lazy.LazyColumn

@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
    LazyColumn(modifier = modifier) {

    }
}
  1. Dalam isi lambda LazyColumn, panggil metode items() dan teruskan affirmationList. Metode items() adalah cara Anda menambahkan item ke LazyColumn. Metode ini agak unik untuk composable ini, dan bukan praktik umum untuk sebagian besar composable.

MainActivity.kt

import androidx.compose.foundation.lazy.items

@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
    LazyColumn(modifier = modifier) {
        items(affirmationList) {

        }
    }
}
  1. Panggilan ke metode items() memerlukan fungsi lambda. Dalam fungsi tersebut, tetapkan parameter affirmation yang mewakili satu item afirmasi dari affirmationList.

MainActivity.kt

@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
    LazyColumn(modifier = modifier) {
        items(affirmationList) { affirmation ->

        }
    }
}
  1. Untuk setiap afirmasi dalam daftar, panggil composable AffirmationCard(). Teruskan affirmation dan objek Modifier dengan atribut padding yang disetel ke 8.dp.

MainActivity.kt

@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
    LazyColumn(modifier = modifier) {
        items(affirmationList) { affirmation ->
            AffirmationCard(
                affirmation = affirmation,
                modifier = Modifier.padding(8.dp)
            )
        }
    }
}

Menampilkan daftar

  1. Pada composable AffirmationsApp, ambil rute tata letak saat ini lalu simpan dalam variabel. Rute ini akan digunakan untuk mengonfigurasi padding nanti.

MainActivity.kt

import com.example.affirmations.data.Datasource

@Composable
fun AffirmationsApp() {
    val layoutDirection = LocalLayoutDirection.current
}
  1. Sekarang, buat composable Surface. Composable ini akan menetapkan padding untuk composable AffirmationsList.

MainActivity.kt

import com.example.affirmations.data.Datasource

@Composable
fun AffirmationsApp() {
    val layoutDirection = LocalLayoutDirection.current
    Surface() {
    }
}
  1. Teruskan Modifier ke composable Surface yang mengisi lebar dan tinggi maksimum induknya, menetapkan padding status bar, serta menyetel padding awal dan akhir ke layoutDirection. Berikut contoh cara menerjemahkan objek LayoutDirection menjadi padding: WindowInsets.safeDrawing.asPaddingValues().calculateStartPadding(layoutDirection).

MainActivity.kt

import com.example.affirmations.data.Datasource

@Composable
fun AffirmationsApp() {
    val layoutDirection = LocalLayoutDirection.current
    Surface(
        Modifier = Modifier
        .fillMaxSize()
        .statusBarsPadding()
        .padding(
            start = WindowInsets.safeDrawing.asPaddingValues()
                    .calculateStartPadding(layoutDirection),
            end = WindowInsets.safeDrawing.asPaddingValues()
                    .calculateEndPadding(layoutDirection),
        ),
    ) {
    }
}
  1. Di lambda untuk composable Surface, panggil composable AffirmationList, lalu teruskan DataSource().loadAffirmations() ke parameter affirmationList.

MainActivity.kt

import com.example.affirmations.data.Datasource

@Composable
fun AffirmationsApp() {
    val layoutDirection = LocalLayoutDirection.current
    Surface(
        Modifier = Modifier
        .fillMaxSize()
        .statusBarsPadding()
        .padding(
            start = WindowInsets.safeDrawing.asPaddingValues()
                    .calculateStartPadding(layoutDirection),
            end = WindowInsets.safeDrawing.asPaddingValues()
                    .calculateEndPadding(layoutDirection),
        ),
    ) {
        AffirmationsList(
            affirmationList = Datasource().loadAffirmations(),
        )
    }
}

Jalankan aplikasi Affirmations di perangkat atau emulator dan lihat produk yang sudah selesai.

286f5132aa155fa6.png

4. Mendapatkan kode solusi

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

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-affirmations.git
$ cd basic-android-kotlin-compose-training-affirmations
$ git checkout intermediate

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

Jika Anda ingin melihat kode solusi, lihat di GitHub.

5. Kesimpulan

Anda sekarang tahu cara membuat kartu, item daftar, dan daftar yang dapat di-scroll menggunakan Jetpack Compose. Ingatlah bahwa ini hanyalah alat dasar untuk membuat daftar. Anda dapat menyalurkan kreativitas dan menyesuaikan item daftar sesuka hati.

Ringkasan

  • Gunakan composable Card untuk membuat item daftar.
  • Ubah UI yang ada dalam composable Card.
  • Buat daftar yang dapat di-scroll menggunakan composable LazyColumn.
  • Buat daftar menggunakan item daftar kustom.