1. 事前準備
Compose for TV 是最新的 UI 架構,用於開發在 Android TV 上執行的應用程式。此架構可享有適用於 TV 應用程式的 Jetpack Compose 所有優勢,更輕鬆地為應用程式建構美觀且實用的使用者介面。Compose for TV 的一些特定優點如下:
- 高度彈性。Compose 可用於建立任何類型的 UI,從簡單的版面配置到複雜的動畫都沒問題。元件可立即使用,但也可以配合應用程式需求自訂及設定樣式。
- 簡化及加速開發作業。Compose 與現有程式碼相容,且可讓開發人員用較少的程式碼建構應用程式。
- 操作直覺:Compose 採用宣告式語法,讓使用者以符合直覺的方式變更使用者介面,以及偵錯、解讀和檢查程式碼。
電視應用程式的常見用途是使用媒體。使用者瀏覽內容目錄,然後選取要觀看的內容。內容可以是電影、電視節目或 Podcast。使用者選取內容後,可能會想查看更多內容資訊,例如簡短說明、播放長度和創作者名稱。在本程式碼研究室中,您可以學到如何使用 Compose for TV 實作目錄瀏覽器畫面和詳細資料畫面。
必要條件
- 具備 Kotlin 語法經驗 (包括 lambda)。
- 具備 Compose 的基本經驗。如果您不熟悉 Compose,請先完成「Jetpack Compose 基本概念」程式碼研究室。
- 具備可組合函式和修飾符的基本知識。
- 使用下列任一裝置執行範例應用程式:
- Android TV 裝置
- 在電視裝置定義類別中含有設定檔的Android 虛擬裝置
建構內容
- 包含目錄瀏覽器畫面和詳細資料畫面的影片播放器應用程式。
- 目錄瀏覽器畫面,顯示使用者可選擇的影片清單。如下圖所示:

- 詳細資料畫面,顯示所選影片的中繼資料,例如標題、說明和長度。如下圖所示:

需求條件
- 最新版 Android Studio
- Android TV 裝置或電視裝置類別中的虛擬裝置
2. 做好準備
如要取得含有本程式碼研究室的主題設定和基本設定程式碼,請執行下列任一操作:
- 複製這個 GitHub 存放區中的程式碼:
$ git clone https://github.com/android/tv-codelabs.git
main 分支版本含有範例程式碼,solution 分支版本則包含解決方案程式碼。
- 下載含有範例程式碼的
main.zip檔案,以及包含解決方案程式碼的solution.zip檔案。
下載程式碼後,請在 Android Studio 中開啟「IntroductionToComposeForTV」專案資料夾。現已準備就緒,可以開始了。
3. 實作目錄瀏覽器畫面
目錄瀏覽器畫面可讓使用者瀏覽電影目錄。您要將目錄瀏覽器實作為可組合函式。您可以在 CatalogBrowser.kt 檔案中找到 CatalogBrowser 可組合函式。您會在這個可組合函式中實作目錄瀏覽器畫面。
範例程式碼含有稱為 CatalogBrowserViewModel 類別的 ViewModel,其中包含幾種屬性和方法,用於擷取描述電影內容的 Movie 物件。您要使用擷取的 Movie 物件實作目錄瀏覽器。
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
}
顯示類別名稱
您可以使用 catalogBrowserViewModel.categoryList 屬性 (即 Category 清單的資料流) 存取類別清單。系統會透過呼叫資料流的 collectAsStateWithLifecycle 方法,將資料流收集為 Compose State 物件。Category 物件包含 name 屬性,是代表類別名稱的 String 值。
如要顯示類別名稱,請按照下列步驟操作:
- 在 Android Studio 中開啟範例程式碼的
CatalogBrowser.kt檔案,然後將LazyColumn可組合函式新增至CatalogBrowser可組合函式。 - 呼叫
catalogBrowserViewModel.categoryList.collectAsStateWithLifeCycle()方法,將資料流收集為State物件。 - 將
categoryList宣告為您在上一個步驟中所建立State物件的委派屬性。 - 使用
categoryList變數做為參數來呼叫items函式。 - 使用類別名稱做為參數來呼叫
Text可組合函式,該參數會做為 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)
}
}
}
顯示每個類別的內容清單
Category 物件還有另一個名為 movieList 的屬性。該屬性是 Movie 物件清單,代表屬於該類別的電影。
如要顯示各個類別的內容清單,請按照下列步驟操作:
- 新增
LazyRow可組合函式,然後將 lambda 傳遞至該函式。 - 在 lambda 中,使用
category.movieList屬性值呼叫items函式,然後將 lambda 傳遞至該函式。 - 在傳遞至
items函式的 lambda 中,使用Movie物件呼叫MovieCard可組合函式。
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)
}
}
}
}
}
選用:調整版面配置
- 如要設定類別之間的間距,請使用
verticalArrangement參數將Arrangement物件傳遞至LazyColumn可組合函式。請透過呼叫Arrangement#spacedBy方法來建立Arrangement物件。 - 如要設定電影資訊卡之間的間距,請使用
horizontalArrangement參數將Arrangement物件傳遞至LazyRow可組合函式。 - 若要為資料欄設定縮排,請使用
contentPadding參數傳遞PaddingValue物件。
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. 實作詳細資料畫面
詳細資料畫面會顯示所選電影的詳細資料。Details.kt 檔案中有 Details 可組合函式。請將程式碼新增至這個函式,以實作詳細資料畫面。
Details.kt
@Composable
fun Details(movie: Movie, modifier: Modifier = Modifier) {
}
顯示電影名稱、電影公司名稱和說明
Movie 物件包含下列三個字串屬性,做為電影的中繼資料:
title:電影名稱。studio:製作電影的公司名稱。description:電影的簡短摘要。
如要在詳細資料畫面上顯示這項中繼資料,請按照下列步驟操作:
- 新增
Column可組合函式,然後使用由Modifier.padding方法建立的Modifier物件,將資料欄周圍的垂直間距設為 32 dp,水平間距設為 48 dp。 - 新增
Text可組合函式以顯示電影標題。 - 新增
Text可組合函式以顯示電影公司名稱。 - 新增
Text可組合函式以顯示電影說明。
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)
}
}
在 Details 可組合函式的參數中指定的 Modifier 物件,會在下一個工作中用到。
顯示與指定 Movie「物件」相關聯的背景圖片
Movie 物件包含 backgroundImageUrl 屬性,表示物件所描述電影的背景圖片位置。
如要顯示特定電影的背景圖片,請按照下列步驟操作:
- 新增
Box可組合函式做為Column可組合函式的包裝函式,其中modifier物件是透過Details可組合函式傳遞。 - 在
Box可組合函式中,呼叫modifier物件的fillMaxSize方法,讓Box可組合函式填入可分配至Details可組合函式的大小上限。 - 將含有下列參數的
AsyncImage可組合函式新增至Box可組合函式:
- 將指定
Movie物件的backgroundImageUrl屬性值設為model參數。 - 將
null傳遞至contentDescription參數。
- 將
ContentScale.Crop物件傳遞至contentScale參數。如要查看不同的ContentScale選項,請參閱「內容縮放」。 - 將
Modifier.fillMaxSize方法的傳回值傳遞至modifier參數。
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)
}
}
}
參照 MaterialTheme 物件,讓主題設定保持一致
MaterialTheme 物件含有用於參照目前主題值的函式,例如 Typography 和 ColorScheme 類別中的值。
如要參照 MaterialTheme 物件以讓主題設定保持一致,請按照下列步驟操作:
- 將
MaterialTheme.typography.displayMedium屬性設為電影標題的文字樣式。 - 將
MaterialTheme.typography.bodySmall屬性設為第二個Text可組合函式的文字樣式。 - 使用
Modifier.background方法,將MaterialTheme.colorScheme.background屬性設為Column可組合函式的背景顏色。
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)
}
}
}
選用:調整版面配置
如要調整 Details 可組合函式的版面配置,請按照下列步驟操作:
- 設定
Box可組合函式,透過fillMaxSize修飾符使用完整的可用空間 - 使用
background修飾符設定Box可組合函式的背景,以便用呼叫Brush.linearGradient函式 (其中含有包含MaterialTheme.colorScheme.background和Color.Transparent的Color物件清單) 所建立的線性漸層填入背景 - 使用
padding修飾符,在Column可組合函式周圍設定48.dp水平和24.dp垂直間距 - 使用
width修飾符 (以0.5f值呼叫Modifier.width函式所建立) 設定Column可組合函式的寬度 - 在第二個
Text可組合函式和第三個Text可組合函式之間,使用Spacer新增8.dp空間。Spacer可組合函式的高度,是透過Modifier.height函式建立的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. 在畫面之間新增導覽
現在您已擁有目錄瀏覽器畫面和詳細資料畫面。使用者在目錄瀏覽器畫面中選取內容後,該畫面就必須轉換為詳細資料畫面。為此,請使用 clickable 修飾符在 MovieCard 可組合函式中加入 event 事件監聽器。當使用者按下方向鍵中間的按鈕時,請使用與 MovieCard 可組合函式相關聯的電影物件做為引數來呼叫 CatalogBrowserViewModel#showDetails 方法。
- 開啟
com.example.tvcomposeintroduction.ui.screens.CatalogBrowser檔案。 - 使用
onClick參數將 lambda 函式傳遞至MovieCard可組合函式。 - 使用與
MovieCard可組合函式相關聯的電影物件呼叫onMovieSelected回呼。
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. 將輪轉介面加入目錄瀏覽器畫面,藉此凸顯精選內容
輪轉介面是一種常見的自動調整式 UI 元件,會在指定的時間長度過後自動更新介面的投影片,通常用來凸顯精選內容。
如要在目錄瀏覽器畫面中新增輪轉介面,藉此凸顯精選內容清單中的電影,請按照下列步驟操作:
- 開啟
com.example.tvcomposeintroduction.ui.screens.CatalogBrowser檔案。 - 呼叫
item函式,將項目新增至LazyColumn可組合函式。 - 在傳遞至
item函式的 lambda 中宣告featuredMovieList做為委派屬性,然後將State物件 (從catalogBrowserViewModel.featuredMovieList屬性收集而來) 設為委派項目。 - 在
item函式中呼叫Carousel可組合函式,然後傳入下列參數:
- 透過
slideCount參數設定featuredMovieList變數的大小。 Modifier物件,用於透過Modifier.fillMaxWidth和Modifier.height方法指定輪轉介面的大小。Carousel可組合函式會藉由將376.dp值傳遞至Modifier.height方法,將高度設為 376 dp。- 透過整數值呼叫的 lambda,代表可見輪轉介面項目的索引。
- 從
featuredMovieList變數和指定的索引值擷取Movie物件。 - 將
Box可組合函式新增至Carousel可組合函式。 - 在
Box可組合函式中新增Text可組合函式,即可顯示電影標題。
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) })
}
}
}
}
}
顯示背景圖片
Box 可組合函式會將一個元件放在另一個元件上。詳情請參閱「版面配置基本概念」一文。
如要顯示背景圖片,請按照下列步驟操作:
- 呼叫
AsyncImage可組合函式,在Text可組合函式之前載入與Movie物件相關聯的背景圖片。 - 更新
Text可組合函式的位置和文字樣式,讓畫面更加清楚。 - 將預留位置設為
AsyncImage可組合函式,以免版面配置位移。範例程式碼含有預留位置做為可繪項目,您可以使用R.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) })
}
}
}
}
}
在詳細資料畫面中新增畫面轉場
您可以在輪轉介面中新增 Button,讓使用者點選按鈕觸發畫面轉換,前往到詳細資料畫面。
如要讓使用者在詳細資料畫面上,查看可見輪轉介面中的電影詳細資料,請按照下列步驟操作:
- 在
Carousel可組合函式的Box可組合函式中呼叫Column可組合函式 - 將
Carousel中的Text可組合函式移至Column可組合函式 - 在
Column可組合函式的Text可組合函式後方呼叫Button可組合函式 - 在
Button可組合函式中,使用R.string.show_details呼叫的stringResource函式傳回值來呼叫Text可組合函式。 - 在傳遞至
Button可組合函式的onClick參數的 lambda 中使用featuredMovie變數呼叫onMovieSelected函式
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) })
}
}
}
}
}
選用:調整版面配置
如要調整輪轉介面的版面配置,請按照下列步驟操作:
- 在
Carousel可組合函式中,以MaterialTheme.colorScheme.background值指派backgroundColor值 - 使用
Box可組合函式納入Column可組合函式 - 將
Alignment.BottomStart值傳遞至Box元件的contentAlignment參數。 - 將
fillMaxSize修飾符傳遞至Box可組合函式的修飾符參數。fillMaxSize修飾符是以Modifier.fillMaxSize()函式建立。 - 透過傳遞至
Box可組合函式的fillMaxSize修飾符呼叫drawBehind()方法 - 在傳遞至
drawBehind修飾符的 lambda 中,以Brush物件 (透過呼叫含有兩個Color物件的清單的Brush.linearGradient函式所建立) 指派brush值。清單是透過呼叫含有backgroundColor值和Color.Transparent值的listOf函式所建立。 - 在傳遞至
drawBehind修飾符的 lambda 中使用brush物件呼叫drawRect,藉此在背景圖片上建立 Srim 層 - 使用透過呼叫含有
20.dp值的Modifier.padding所建立的padding修飾符,指定Column可組合函式的邊框間距。 - 在
Column可組合函式的Text可組合函式和Button可組合函式之間,新增含有20.dp值的Spacer可組合函式
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. 取得解決方案程式碼
如要下載本程式碼研究室的解決方案程式碼,請執行下列任一操作:
- 點選下方按鈕即可將其下載為 ZIP 檔案,然後解壓縮並在 Android Studio 中開啟。
- 使用 Git 擷取檔案:
$ git clone https://github.com/android/tv-codelabs.git $ cd tv-codelabs $ git checkout solution $ cd IntroductionToComposeForTV
8. 恭喜。
恭喜!您已瞭解 Compose for TV 的基本概念:
- 如何透過結合 LazyColumn 和 LazyLow,實作顯示內容清單的螢幕畫面。
- 實作顯示內容詳細資料的基本畫面。
- 如何在兩個畫面之間新增畫面轉場。