1. Sebelum memulai
Compose untuk TV adalah framework UI terbaru untuk mengembangkan aplikasi yang berjalan di Android TV. Framework ini mendapatkan semua manfaat Jetpack Compose untuk aplikasi TV sehingga mem-build UI yang indah dan fungsional untuk aplikasi Anda menjadi lebih mudah. Beberapa manfaat khusus Compose untuk TV mencakup hal berikut:
- Fleksibilitas. Compose dapat digunakan untuk membuat jenis UI apa pun, mulai dari tata letak yang sederhana hingga animasi yang kompleks. Komponen dapat langsung difungsikan, tetapi juga dapat disesuaikan dan ditata agar sesuai dengan kebutuhan aplikasi Anda.
- Pengembangan yang disederhanakan dan dipercepat. Compose kompatibel dengan kode yang sudah ada dan memungkinkan developer membuat aplikasi dengan lebih sedikit kode.
- Intuitif: Compose menggunakan sintaksis deklaratif yang membuatnya intuitif untuk mengubah UI Anda, serta melakukan debug, memahami, dan meninjau kode Anda.
Kasus penggunaan umum untuk aplikasi TV adalah konsumsi media. Pengguna menjelajahi katalog konten dan memilih konten yang ingin ditonton. Konten dapat berupa film, acara TV, atau podcast. Setelah pengguna memilih konten, mereka mungkin ingin melihat informasi lebih lanjut tentang konten tersebut, seperti deskripsi singkat, durasi pemutaran, dan nama kreator. Dalam codelab ini, Anda akan mempelajari cara menerapkan layar browser katalog dan layar detail dengan Compose untuk TV.
Prasyarat
- Pengalaman dengan sintaksis Kotlin, termasuk lambda.
- Pengalaman dasar dengan Compose. Jika Anda tidak terbiasa dengan Compose, selesaikan codelab Dasar-dasar Jetpack Compose.
- Pengetahuan dasar tentang composable dan pengubah.
- Salah satu perangkat berikut untuk menjalankan aplikasi contoh:
- Perangkat Android TV
- Perangkat virtual Android dengan profil dalam kategori definisi perangkat TV
Yang Anda bangun
- Aplikasi pemutar video dengan layar browser katalog dan layar detail.
- Layar browser katalog yang menampilkan daftar video yang dapat dipilih pengguna. Tampilannya akan terlihat seperti gambar berikut:
- Layar detail yang menunjukkan metadata video yang dipilih, seperti judul, deskripsi, dan durasi. Tampilannya akan terlihat seperti gambar berikut:
Yang Anda perlukan
- Versi terbaru Android Studio
- Perangkat Android TV atau perangkat virtual dalam kategori perangkat TV
2. Memulai persiapan
Untuk mendapatkan kode yang berisi tema dan penyiapan dasar untuk codelab ini, lakukan salah satu hal berikut:
- Clone kode dari repositori GitHub ini:
$ git clone https://github.com/android/tv-codelabs.git
Cabang main
berisi kode awal dan cabang solution
berisi kode solusi.
- Download file
main.zip
, yang berisi kode awal, dan filesolution.zip
, yang berisi kode solusi.
Setelah berhasil mendownload kode, buka folder project IntroductionToComposeForTV di Android Studio. Sekarang Anda siap untuk memulai.
3. Menerapkan layar browser katalog
Layar browser katalog memungkinkan pengguna menjelajahi katalog film. Anda mengimplementasikan browser katalog sebagai fungsi composable. Anda dapat menemukan fungsi composable CatalogBrowser
dalam file CatalogBrowser.kt
. Anda akan menerapkan layar browser katalog dalam fungsi composable ini.
Kode awal memiliki ViewModel yang disebut class CatalogBrowserViewModel
yang memiliki beberapa atribut dan metode untuk mengambil objek Movie
yang mendeskripsikan konten film. Anda mengimplementasikan browser katalog dengan objek Movie
yang diambil.
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
}
Menampilkan nama kategori
Anda dapat mengakses daftar kategori dengan atribut catalogBrowserViewModel.categoryList
yang merupakan alur daftar Category
. Alur ini dikumpulkan sebagai objek Compose State
dengan memanggil metode collectAsStateWithLifecycle
. Objek Category
memiliki atribut name
, yang merupakan nilai String
yang mewakili nama kategori.
Untuk menampilkan nama kategori, ikuti langkah-langkah berikut:
- Di Android Studio, buka file
CatalogBrowser.kt
kode awal, lalu tambahkan fungsi composableLazyColumn
ke fungsi composableCatalogBrowser
. - Panggil metode
catalogBrowserViewModel.categoryList.collectAsStateWithLifeCycle()
untuk mengumpulkan alur sebagai objekState
. - Deklarasikan
categoryList
sebagai properti yang didelegasikan dari objekState
yang Anda buat di langkah sebelumnya. - Panggil fungsi
items
dengan variabelcategoryList
sebagai parameter. - Panggil fungsi composable
Text
dengan nama kategori sebagai parameter yang diteruskan sebagai argumen lambda.
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by catalogBrowserViewModel.categoryList.collectAsStateWithLifecycle()
LazyColumn(modifier = modifier) {
items(categoryList) { category ->
Text(text = category.name)
}
}
}
Menampilkan daftar konten untuk setiap kategori
Objek Category
memiliki atribut lain yang disebut movieList
. Atribut ini adalah daftar objek Movie
yang mewakili film yang termasuk dalam kategori tersebut.
Untuk menampilkan daftar konten untuk setiap kategori, ikuti langkah-langkah berikut:
- Tambahkan fungsi composable
LazyRow
, lalu teruskan lambda ke fungsi tersebut. - Di lambda, panggil fungsi
items
dengancategory
.Nilai atributmovieList
, lalu teruskan lambda ke nilai tersebut. - Di lambda yang diteruskan ke fungsi
items
, panggil fungsi composableMovieCard
dengan objekMovie
.
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsStateWithLifecycle()
LazyColumn(modifier = modifier) {
items(categoryList) { category ->
Text(text = category.name)
LazyRow {
items(category.movieList) {movie ->
MovieCard(movie = movie)
}
}
}
}
}
Opsional: Menyesuaikan tata letak
- Untuk menetapkan jarak antar-kategori, teruskan objek
Arrangement
ke fungsi composableLazyColumn
dengan parameterverticalArrangement
. ObjekArrangement
dibuat dengan memanggil metodeArrangement#spacedBy
. - Untuk menetapkan jarak antar-kartu film, teruskan objek
Arrangement
ke fungsi composableLazyRow
dengan parameterhorizontalArrangement
. - Untuk menetapkan indentasi ke kolom, teruskan objek
PaddingValue
dengan parametercontentPadding
.
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsStateWithLifeCycle()
LazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
items(categoryList) { category ->
Text(text = category.name)
LazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie)
}
}
}
}
}
4. Menerapkan layar detail
Layar detail menampilkan detail film yang dipilih. Ada fungsi composable Details
dalam file Details.kt
. Anda akan menambahkan kode ke fungsi ini untuk menerapkan layar detail.
Details.kt
@Composable
fun Details(movie: Movie, modifier: Modifier = Modifier) {
}
Menampilkan judul film, nama studio, dan deskripsi
Objek Movie
memiliki tiga atribut string berikut sebagai metadata film:
title
. Judul film.studio
. Nama studio yang memproduksi film.description
. Ringkasan singkat film.
Untuk menampilkan metadata ini di layar detail, ikuti langkah-langkah berikut:
- Tambahkan fungsi composable
Column
, lalu tetapkan jarak vertikal 32 dp dan horizontal 48 dp di sekitar kolom dengan objekModifier
yang dibuat oleh metodeModifier.padding
. - Tambahkan fungsi composable
Text
untuk menampilkan judul film. - Tambahkan fungsi composable
Text
untuk menampilkan nama studio. - Tambahkan fungsi composable
Text
untuk menampilkan deskripsi film.
Details.kt
@Composable
fun Details(movie: Movie, modifier: Modifier = Modifier) {
Column(
modifier = Modifier
.padding(vertical = 32.dp, horizontal = 48.dp)
) {
Text(text = movie.title)
Text(text = movie.studio)
Text(text = movie.description)
}
}
Objek Modifier
yang ditentukan dalam parameter fungsi composable Details
digunakan dalam tugas berikutnya.
Menampilkan gambar latar yang terkait dengan objek Movie
tertentu
Objek Movie
memiliki atribut backgroundImageUrl
yang menunjukkan lokasi gambar latar untuk film yang dijelaskan oleh objek.
Agar gambar latar untuk film tertentu dapat ditampilkan, ikuti langkah-langkah berikut:
- Tambahkan fungsi composable
Box
sebagai wrapper fungsi composableColumn
dengan objekmodifier
yang diteruskan melalui fungsi composableDetails
. - Dalam fungsi composable
Box
, panggil metodefillMaxSize
objekmodifier
untuk membuat fungsi composableBox
mengisi ukuran maksimum yang dapat dialokasikan ke fungsi composableDetails
. - Tambahkan fungsi composable
AsyncImage
dengan parameter berikut ke fungsi composableBox
:
- Setel nilai atribut
backgroundImageUrl
dari objekMovie
yang diberikan ke parametermodel
. - Teruskan
null
ke parametercontentDescription
.
- Teruskan objek
ContentScale.Crop
ke parametercontentScale
. Untuk melihat opsiContentScale
yang berbeda, lihat Skala konten. - Teruskan nilai return metode
Modifier.fillMaxSize
ke parametermodifier
.
Details.kt
@Composable
fun Details(movie: Movie, modifier: Modifier = Modifier) {
Box(modifier = modifier.fillMaxSize()) {
AsyncImage(
model = movie.cardImageUrl,
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
Column {
Text(
text = movie.title,
)
Text(
text = movie.studio,
)
Text(text = movie.description)
}
}
}
Lihat objek MaterialTheme
untuk penerapan tema yang konsisten
Objek MaterialTheme
berisi fungsi untuk mereferensikan nilai tema saat ini, seperti yang ada di class Typography
dan ColorScheme
.
Untuk melihat objek MaterialTheme
agar temanya konsisten, ikuti langkah-langkah berikut:
- Tetapkan properti
MaterialTheme.typography.displayMedium
ke gaya teks judul film. - Setel properti
MaterialTheme.typography.bodySmall
ke gaya teks dari fungsi composableText
kedua. - Tetapkan properti
MaterialTheme.colorScheme.background
ke warna latar belakang fungsi composableColumn
dengan metodeModifier.background
.
Details.kt
@Composable
fun Details(movie: Movie, modifier: Modifier = Modifier) {
Box(modifier = modifier.fillMaxSize()) {
AsyncImage(
model = movie.cardImageUrl,
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
Column(
modifier = Modifier
.background(MaterialTheme.colorScheme.background),
) {
Text(
text = movie.title,
style = MaterialTheme.typography.displayMedium,
)
Text(
text = movie.studio,
style = MaterialTheme.typography.bodySmall,
)
Text(text = movie.description)
}
}
}
Opsional: Menyesuaikan tata letak
Untuk menyesuaikan tata letak fungsi composable Details
, ikuti langkah-langkah berikut:
- Tetapkan fungsi composable
Box
untuk menggunakan seluruh ruang yang tersedia dengan pengubahfillMaxSize
- Tetapkan latar belakang fungsi composable
Box
dengan pengubahbackground
untuk mengisi latar belakang dengan gradien linear yang dibuat dengan memanggil fungsiBrush.linearGradient
dengan daftar objekColor
yang berisi nilaiMaterialTheme.colorScheme.background
danColor.Transparent
- Tetapkan jarak horizontal
48.dp
dan vertikal24.dp
di sekitar fungsi composableColumn
dengan Pengubahpadding
- Tetapkan dengan fungsi composable
Column
dengan pengubahwidth
yang dibuat dengan memanggil fungsiModifier.width
dengan nilai0.5f
- Tambahkan jarak
8.dp
antar fungsi composableText
kedua dan composableText
ketiga denganSpacer
. Tinggi fungsi composableSpacer
ditentukan dengan pengubahheight
yang dibuat dengan fungsiModifier.height
Details.kt
@Composable
fun Details(movie: Movie, modifier: Modifier = Modifier) {
Box(modifier = modifier.fillMaxSize()) {
AsyncImage(
model = movie.cardImageUrl,
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
Box(
modifier = Modifier
.background(
Brush.linearGradient(
listOf(
MaterialTheme.colorScheme.background,
Color.Transparent
)
)
)
.fillMaxSize()
) {
Column(
modifier = Modifier
.padding(horizontal = 48.dp, vertical = 24.dp)
.fillMaxWidth(0.5f)
) {
Text(
text = movie.title,
style = MaterialTheme.typography.displayMedium,
)
Text(
text = movie.studio,
style = MaterialTheme.typography.bodySmall,
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = movie.description,
)
}
}
}
}
5. Menambahkan navigasi antar-layar
Sekarang Anda memiliki browser katalog dan layar detail. Setelah pengguna memilih konten di layar browser katalog, layar harus bertransisi ke layar detail. Untuk memungkinkan hal ini, gunakan pengubah clickable
untuk menambahkan pemroses event
ke fungsi composable MovieCard
. Saat tombol tengah dari tombol arah ditekan, metode CatalogBrowserViewModel#showDetails
dipanggil dengan objek film yang terkait dengan fungsi composable MovieCard
sebagai argumen.
- Buka file
com.example.tvcomposeintroduction.ui.screens.CatalogBrowser
. - Teruskan fungsi lambda ke fungsi composable
MovieCard
dengan parameteronClick
. - Panggil callback
onMovieSelected
dengan objek film yang terkait dengan fungsi composableMovieCard
.
CatalogBrowser.kt
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsStateWithLifecycle()
LazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
items(categoryList) { category ->
Text(text = category.name)
LazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie, onClick = { onMovieSelected(movie) })
}
}
}
}
}
6. Menambahkan carousel ke layar browser katalog untuk menandai konten unggulan
Carousel adalah komponen UI yang umum diadaptasikan, yang otomatis mengupdate slide setelah durasi yang ditentukan. Atribut ini biasanya digunakan untuk menyoroti konten unggulan.
Untuk menambahkan carousel ke layar katalog guna menyoroti film dalam daftar konten unggulan, ikuti langkah-langkah berikut:
- Buka file
com.example.tvcomposeintroduction.ui.screens.CatalogBrowser
. - Panggil fungsi
item
untuk menambahkan item ke fungsi composableLazyColumn
. - Deklarasikan
featuredMovieList
sebagai properti yang didelegasikan dalam lambda yang diteruskan ke fungsiitem
, lalu tetapkan objekState
yang akan didelegasikan, yang dikumpulkan dari atributcatalogBrowserViewModel.featuredMovieList
. - Panggil fungsi composable
Carousel
di dalam fungsiitem
, lalu teruskan parameter berikut:
- Ukuran variabel
featuredMovieList
melalui parameterslideCount
. - Objek
Modifier
untuk menentukan ukuran carousel dengan metodeModifier.fillMaxWidth
danModifier.height
. Fungsi composableCarousel
menggunakan tinggi 376 dp dengan meneruskan nilai376.dp
ke metodeModifier.height
. - Lambda yang dipanggil dengan nilai bilangan bulat yang menunjukkan indeks item carousel yang terlihat.
- Ambil objek
Movie
dari variabelfeaturedMovieList
dan nilai indeks yang diberikan. - Tambahkan fungsi composable
Box
ke fungsi composableCarousel
. - Tambahkan fungsi composable
Text
ke fungsi composableBox
untuk menampilkan judul film.
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsStateWithLifecycle()
LazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
item {
val featuredMovieList by catalogBrowserViewModel.featuredMovieList.collectAsStateWithLifecycle()
Carousel(
slideCount = featuredMovieList.size,
modifier = Modifier
.fillMaxWidth()
.height(376.dp)
) { indexOfCarouselSlide ->
val featuredMovie =
featuredMovieList[indexOfCarouselSlide]
Box {
Text(text = featuredMovie.title)
}
}
}
items(categoryList) { category ->
Text(text = category.name)
LazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie, onClick = { onMovieSelected(movie) })
}
}
}
}
}
Menampilkan gambar latar
Fungsi composable Box
menempatkan satu komponen di atas komponen lain. Baca Dasar-dasar tata letak untuk mengetahui detail selengkapnya.
Untuk menampilkan gambar latar, ikuti langkah-langkah berikut:
- Panggil fungsi composable
AsyncImage
untuk memuat gambar latar yang terkait dengan objekMovie
sebelum fungsi composableText
. - Perbarui posisi dan gaya teks fungsi composable
Text
untuk visibilitas yang lebih baik. - Tetapkan placeholder ke fungsi composable
AsyncImage
untuk menghindari pergeseran tata letak. Kode awal memiliki placeholder sebagai drawable yang dapat Anda referensikan denganR.drawable.placeholder
.
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsStateWithLifecycle()
LazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
item {
val featuredMovieList by catalogBrowserViewModel.featuredMovieList.collectAsStateWithLifecycle()
Carousel(
slideCount = featuredMovieList.size,
modifier = Modifier
.fillMaxWidth()
.height(376.dp),
) { indexOfCarouselItem ->
val featuredMovie = featuredMovieList[indexOfCarouselItem]
Box{
AsyncImage(
model = featuredMovie.backgroundImageUrl,
contentDescription = null,
placeholder = painterResource(
id = R.drawable.placeholder
),
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize(),
)
Text(text = featuredMovie.title)
}
}
}
items(categoryList) { category ->
Text(text = category.name)
LazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie, onClick = { onMovieSelected(movie) })
}
}
}
}
}
Menambahkan transisi layar ke layar detail
Anda dapat menambahkan Button
ke carousel agar pengguna dapat memicu transisi layar ke layar detail dengan mengklik tombol.
Untuk mengizinkan pengguna melihat detail film di carousel yang terlihat di layar detail, ikuti langkah-langkah berikut:
- Panggil fungsi composable
Column
di composableBox
di composableCarousel
- Pindahkan composable
Text
diCarousel
ke fungsi composableColumn
- Panggil fungsi composable
Button
setelah fungsi composableText
di fungsi composableColumn
- Panggil fungsi composable
Text
dalam fungsi composableButton
dengan nilai yang ditampilkan dari fungsistringResource
yang dipanggil denganR.string.show_details
. - Panggil fungsi
onMovieSelected
dengan variabelfeaturedMovie
di lambda yang diteruskan ke parameteronClick
dari fungsi composableButton
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsStateWithLifecycle()
LazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
item {
val featuredMovieList by catalogBrowserViewModel.featuredMovieList.collectAsStateWithLifecycle()
Carousel(
slideCount = featuredMovieList.size,
modifier = Modifier
.fillMaxWidth()
.height(376.dp),
) { indexOfCarouselItem ->
val featuredMovie = featuredMovieList[indexOfCarouselItem]
Box {
AsyncImage(
model = featuredMovie.backgroundImageUrl,
contentDescription = null,
placeholder = painterResource(
id = R.drawable.placeholder
),
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize(),
)
Column {
Text(text = featuredMovie.title)
Button(onClick = { onMovieSelected(featuredMovie) }) {
Text(text = stringResource(id = R.string.show_details))
}
}
}
}
}
items(categoryList) { category ->
Text(text = category.name)
LazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie, onClick = { onMovieSelected(movie) })
}
}
}
}
}
Opsional: Menyesuaikan tata letak
Untuk menyesuaikan tata letak carousel, ikuti langkah-langkah berikut:
- Tetapkan nilai
backgroundColor
dengan nilaiMaterialTheme.colorScheme.background
dalam fungsi composableCarousel
- Gabungkan fungsi composable
Column
dengan composableBox
- Teruskan nilai
Alignment.BottomStart
ke parametercontentAlignment
komponenBox
. - Teruskan pengubah
fillMaxSize
ke parameter pengubah fungsi composableBox
. PengubahfillMaxSize
dibuat dengan fungsiModifier.fillMaxSize()
. - Panggil metode
drawBehind()
di atas pengubahfillMaxSize
yang diteruskan ke composableBox
- Di lambda yang diteruskan ke
drawBehind
pengubah, tetapkan nilaibrush
dengan objekBrush
yang dibuat dengan memanggil fungsiBrush.linearGradient
dengan daftar dua objekColor
. Daftar ini dibuat dengan memanggil fungsilistOf
dengan nilaibackgroundColor
dan nilaiColor.Transparent
. - Panggil
drawRect
dengan objekbrush
di lambda yang diteruskan ke pengubahdrawBehind
untuk membuat lapisan srim di atas gambar latar - Tentukan padding fungsi composable
Column
dengan pengubahpadding
yang dibuat dengan memanggilModifier.padding
dengan nilai20.dp
. - Tambahkan fungsi composable
Spacer
dengan nilai20.dp
antara composableText
dan composableButton
dalam fungsi composableColumn
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by catalogBrowserViewModel.categoryList.collectAsStateWithLifecycle()
LazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(32.dp),
contentPadding = PaddingValues(horizontal = 58.dp, vertical = 36.dp)
) {
item {
val featuredMovieList by
catalogBrowserViewModel.featuredMovieList.collectAsStateWithLifecycle()
Carousel(
itemCount = featuredMovieList.size,
modifier = Modifier
.fillMaxWidth()
.height(376.dp),
) { indexOfCarouselItem ->
val featuredMovie = featuredMovieList[indexOfCarouselItem]
val backgroundColor = MaterialTheme.colorScheme.background
Box {
AsyncImage(
model = featuredMovie.backgroundImageUrl,
contentDescription = null,
placeholder = painterResource(
id = R.drawable.placeholder
),
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize(),
)
Box(
contentAlignment = Alignment.BottomStart,
modifier = Modifier
.fillMaxSize()
.drawBehind {
val brush = Brush.horizontalGradient(
listOf(backgroundColor, Color.Transparent)
)
drawRect(brush)
}
) {
Column(
modifier = Modifier.padding(20.dp)
) {
Text(
text = featuredMovie.title,
style = MaterialTheme.typography.displaySmall
)
Spacer(modifier = Modifier.height(28.dp))
Button(onClick = { onMovieSelected(featuredMovie) }) {
Text(text = stringResource(id = R.string.show_details))
}
}
}
}
}
}
items(categoryList) { category ->
Text(text = category.name)
LazyRow(
horizontalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.height(200.dp)
) {
items(category.movieList) { movie ->
MovieCard(
movie,
onClick = {
onMovieSelected(it)
}
)
}
}
}
}
}
7. Mendapatkan kode solusi
Untuk mendownload kode solusi untuk codelab ini, lakukan salah satu hal berikut:
- Klik tombol berikut untuk mendownloadnya sebagai file zip, lalu ekstrak dan buka di Android Studio.
- Ambil dengan Git:
$ git clone https://github.com/android/tv-codelabs.git $ cd tv-codelabs $ git checkout solution $ cd IntroductionToComposeForTV
8. Selamat.
Selamat! Anda telah mempelajari dasar-dasar Compose untuk TV:
- Cara menerapkan layar untuk menampilkan daftar konten dengan menggabungkan LazyColumn dan LazyLow.
- Implementasi layar dasar untuk menampilkan detail konten.
- Cara menambahkan transisi layar antara dua layar.