1. 始める前に
Compose for TV は、Android TV で動作するアプリを開発するための最新の UI フレームワークです。TV アプリ向け Jetpack Compose のすべてのメリットを活用できるため、アプリの美しく機能性の高い UI の作成が容易になります。Compose for TV の具体的なメリットは次のとおりです。
- 柔軟性 Compose を使用すると、シンプルなレイアウトから複雑なアニメーションまで、あらゆる種類の UI を作成できます。コンポーネントはすぐに使用できますが、アプリのニーズに合わせたカスタマイズやスタイル設定も可能です。
- 開発の簡素化と加速Compose は既存のコードと互換性があるため、デベロッパーは少ないコードでアプリを構築できます。
- 直感的: Compose では、UI の変更とコードのデバッグ、理解、レビューを直感的に行える宣言型構文が使用されています。
TV アプリの一般的なユースケースはメディア消費です。ユーザーはコンテンツ カタログを参照して、視聴するコンテンツを選択します。コンテンツには、ムービー、テレビ番組、ポッドキャストなどがあります。ユーザーがコンテンツの選択を終えると、簡単な説明、再生時間、クリエイターの名前などの詳細情報が表示される可能性があります。この Codelab では、Compose for TV を使用してカタログ ブラウザ画面と詳細画面を実装する方法を学びます。
前提条件
- ラムダを含む Kotlin 構文の使用経験。
- Compose に関する基本的な経験。Compose に慣れていない場合は、Jetpack Compose の基本の Codelab を修了してください。
- コンポーザブルと修飾子に関する基本的な知識。
構築内容
- カタログ ブラウザ画面と詳細画面を備えた動画プレーヤー アプリ。
- ユーザーが選択できる動画の一覧が表示されるカタログ ブラウザ画面。次の画像のように表示されます。
- タイトル、説明、長さなど、選択した動画のメタデータを表示する詳細画面。次の画像のように表示されます。
必要なもの
- Android Studio の最新バージョン
2. セットアップする
この Codelab のテーマ設定と基本設定を含むコードを取得するには、次のいずれかを行います。
- この GitHub リポジトリからコードのクローンを作成します。
$ git clone https://github.com/android/tv-codelabs.git
main
ブランチにはスターター コードが含まれ、solution
ブランチには解答コードが含まれます。
- スターター コードを含む
main.zip
ファイルと、解答コードを含むsolution.zip
ファイルをダウンロードします。
コードがダウンロードされたところで、Android Studio で IntroductionToComposeForTV プロジェクト フォルダを開きます。これで準備が整いました。
3.カタログ ブラウザ画面を実装する
カタログ ブラウザ画面では、映画のカタログをブラウジングできます。カタログ ブラウザを Composable
関数として実装します。CatalogBrowser
Composable
関数は CatalogBrowser.kt
ファイルにあります。この Composable
関数で、カタログ ブラウザ画面を実装します。
スターター コードには、CatalogBrowserViewModel
クラスと呼ばれる ViewModel があります。このクラスには、映画のコンテンツを記述する Movie
オブジェクトを取得するための属性とメソッドがいくつかあります。取得した Movie
オブジェクトを使用してカタログ ブラウザを実装します。
CatalogBrowser.kt
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.material3.ExperimentalTvMaterial3Api
import com.example.tvcomposeintroduction.data.Movie
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
}
カテゴリ名を表示する
Category
リストのフローである catalogBrowserViewModel.categoryList
属性を使用して、カテゴリのリストにアクセスできます。フローは、collectAsState
メソッドを呼び出して Compose State
オブジェクトとして収集されます。Category
オブジェクトには name
属性があります。この属性は、カテゴリ名を表す String
値です。
カテゴリ名を表示する手順は次のとおりです。
- Android Studio でスターター コードの
CatalogBrowser.kt
ファイルを開き、TvLazyColumn
Composable
関数をCatalogBrowser
Composable
関数に追加します。 catalogBrowserViewModel.categoryList.collectAsState()
メソッドを呼び出して、フローをState
オブジェクトとして収集します。categoryList
は、前の手順で作成したState
オブジェクトの委任プロパティとして宣言します。categoryList
変数をパラメータとしてitems
関数を呼び出します。- ラムダの引数として渡されるパラメータとして、カテゴリ名を指定して
Text
Composable
関数を呼び出します。
CatalogBrowser.kt
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import com.example.tvcomposeintroduction.data.Movie
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsState()
TvLazyColumn(modifier = modifier) {
items(categoryList) { category ->
Text(text = category.name)
}
}
}
各カテゴリのコンテンツ リストを表示する
Category
オブジェクトには、movieList
という属性があります。この属性は、カテゴリに属する映画を表す Movie
オブジェクトのリストです。
各カテゴリのコンテンツ リストを表示する手順は次のとおりです。
TvLazyRow
Composable
関数を追加して、ラムダを渡します。- ラムダで、
category
を使用してitems
関数を呼び出します。movieList
属性値を取得し、ラムダを渡します。 items
関数に渡されたラムダで、Movie
オブジェクトを指定してMovieCard
Composable
関数を呼び出します。
CatalogBrowser.kt
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.TvLazyRow
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import com.example.tvcomposeintroduction.data.Movie
import com.example.tvcomposeintroduction.ui.components.MovieCard
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsState()
TvLazyColumn(modifier = modifier) {
items(categoryList) { category ->
Text(text = category.name)
TvLazyRow {
items(category.movieList) {movie ->
MovieCard(movie = movie)
}
}
}
}
}
省略可: レイアウトを調整する
- カテゴリ間にギャップを設定するには、
verticalArrangement
パラメータでArrangement
オブジェクトをTvLazyColumn
Composable
関数に渡します。Arrangement
オブジェクトは、Arrangement#spacedBy
メソッドを呼び出して作成されます。 - 映画カードの間隔を設定するには、
horizontalArrangement
パラメータを使用してArrangement
オブジェクトをTvLazyRow
Composable
関数に渡します。 - 列にインデントを設定するには、
contentPadding
パラメータでPaddingValue
オブジェクトを渡します。
CatalogBrowser.kt
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.TvLazyRow
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import com.example.tvcomposeintroduction.data.Movie
import com.example.tvcomposeintroduction.ui.components.MovieCard
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsState()
TvLazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
items(categoryList) { category ->
Text(text = category.name)
TvLazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie)
}
}
}
}
}
4. 詳細画面を実装する
詳細画面に、選択した映画の詳細が表示されます。Details.kt
ファイルには、Details
Composable
関数があります。この関数にコードを追加して、詳細画面を実装します。
Details.kt
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.tv.material3.ExperimentalTvMaterial3Api
import com.example.tvcomposeintroduction.data.Movie
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun Details(movie: Movie, modifier: Modifier = Modifier) {
}
ムービーのタイトル、スタジオ名、説明を表示する
Movie
オブジェクトには、映画のメタデータとして次の 3 つの文字列属性があります。
title
。映画のタイトル。studio
。映画を制作したスタジオの名前。description
。映画の簡単な要約。
このメタデータを詳細画面に表示する手順は次のとおりです。
Column
Composable
関数を追加し、Modifier.padding
メソッドで作成したModifier
オブジェクトを使用して、縦方向の 32 dp と横方向の 48 dp のクリアランスを列に設定します。- 映画のタイトルを表示するには、
Text
Composable
関数を追加します。 Text
Composable
関数を追加して、スタジオ名を表示します。- 映画の説明を表示する
Text
Composable
関数を追加します。
Details.kt
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import com.example.tvcomposeintroduction.data.Movie
@OptIn(ExperimentalTvMaterial3Api::class)
@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.title)
}
}
Details
Composable
関数のパラメータで指定された Modifier
オブジェクトは、次のタスクで使用します。
特定の Movie
オブジェクトに関連付けられている背景画像を表示する
Movie
オブジェクトには backgroundImageUrl
属性があり、そのオブジェクトで記述されている映画の背景画像の場所が示されます。
特定の映画の背景画像を表示する手順は次のとおりです。
Box
Composable
関数をColumn
Composable
関数のラッパーとして追加し、modifier
オブジェクトをDetails
Composable
関数を通じて渡します。Box
Composable
関数で、modifier
オブジェクトのfillMaxSize
メソッドを呼び出して、Box
Composable
関数で、Details
Composable
関数に割り当てることのできる最大サイズを満たせるようにします。- 次のパラメータを含む
AsyncImage
Composable
関数をBox
Composable
関数に追加します。
- 指定された
Movie
オブジェクトのbackgroundImageUrl
属性の値をmodel
パラメータに設定します。 null
をcontentDescription
パラメータに渡します。
ContentScale.Crop
オブジェクトをcontentScale
パラメータに渡します。さまざまなContentScale
オプションについては、コンテンツ スケールをご覧ください。Modifier.fillMaxSize
メソッドの戻り値をmodifier
パラメータに渡します。Modifier.padding
メソッドを呼び出して作成されたModifier
オブジェクトを設定することで、列に 32 dp の垂直方向と 48 dp の水平方向のクリアランスを設定します。
Details.kt
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import coil.compose.AsyncImage
import com.example.tvcomposeintroduction.data.Movie
@OptIn(ExperimentalTvMaterial3Api::class)
@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
.padding(vertical = 32.dp, horizontal = 48.dp)
) {
Text(
text = movie.title,
)
Text(
text = movie.studio,
)
Text(
text = movie.title,
)
}
}
}
一貫性のあるテーマ設定については、MaterialTheme
オブジェクトを参照してください。
MaterialTheme
オブジェクトには、現在のテーマ値を参照する関数(Typography
クラスや [ColorScheme
][ColorScheme] クラスなど)が含まれています。
テーマ設定の一貫性を保つために MaterialTheme
オブジェクトを参照するには、次の手順を行います。
MaterialTheme.typography.headlineLarge
プロパティに、映画のタイトルのテキスト スタイルを設定します。MaterialTheme.typography.headlineMedium
プロパティに、他の 2 つのText
Composable
関数のテキスト スタイルを設定します。Modifier.background
メソッドで、MaterialTheme.colorScheme.background
プロパティをColumn
Composable
関数の背景色に設定します。
[ColorScheme]: /reference/kotlin/androidx/tv/material3/ColorScheme)
Details.kt
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
import coil.compose.AsyncImage
import com.example.tvcomposeintroduction.data.Movie
@OptIn(ExperimentalTvMaterial3Api::class)
@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
.padding(vertical = 32.dp, horizontal = 48.dp)
) {
Text(
text = movie.title,
style = MaterialTheme.typography.headlineLarge,
)
Text(
text = movie.studio,
style = MaterialTheme.typography.headlineMedium,
)
Text(
text = movie.title,
style = MaterialTheme.typography.headlineMedium,
)
}
}
}
5. 画面間のナビゲーションを追加する
これで、カタログ ブラウザと詳細画面が表示されます。ユーザーがカタログ ブラウザ画面でコンテンツを選択した後は、詳細画面に遷移する必要があります。そのためには、clickable
修飾子を使用して、event
リスナーを MovieCard
Composable
関数に追加します。十字キーの中央ボタンが押されると、MovieCard
Composable
関数に関連付けられたムービー オブジェクトを引数として、CatalogBrowserViewModel#showDetails
メソッドが呼び出されます。
com.example.tvcomposeintroduction.ui.screens.CatalogBrowser
ファイルを開きます。- ラムダ関数を
onClick
パラメータを指定したMovieCard
Composable
関数に渡します。 MovieCard
Composable
関数に関連付けられた映画オブジェクトを指定してonMovieSelected
コールバックを呼び出します。
CatalogBrowser.kt
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.TvLazyRow
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import com.example.tvcomposeintroduction.data.Movie
import com.example.tvcomposeintroduction.ui.components.MovieCard
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsState()
TvLazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
items(categoryList) { category ->
Text(text = category.name)
TvLazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie, onClick = { onMovieSelected(movie) })
}
}
}
}
}
6. カタログ ブラウザの画面にカルーセルを追加して、注目のコンテンツをハイライト表示する
カルーセルは、指定された時間が経過するとスライドを自動的に更新する、適応性の高い UI コンポーネントです。通常は、注目のコンテンツをハイライト表示するために使用します。
カルーセルをカタログ ブラウザ画面に追加して、注目のコンテンツ リストで映画をハイライトする手順は次のとおりです。
com.example.tvcomposeintroduction.ui.screens.CatalogBrowser
ファイルを開きます。item
関数を呼び出して、アイテムをTvLazyColumn
Composable
関数に追加します。item
関数に渡されたラムダ内の委任プロパティとしてfeaturedMovieList
を宣言し、catalogBrowserViewModel.featuredMovieList
属性から収集されるState
オブジェクトを委任に設定します。item
関数内でCarousel
Composable
関数を呼び出し、次のパラメータを渡します。
slideCount
パラメータを介したfeaturedMovieList
変数のサイズ。Modifier.fillMaxWidth
メソッドとModifier.height
メソッドでカルーセル サイズを指定するためのModifier
オブジェクト。Carousel
Composable
関数は、376.dp
の値をModifier.height
メソッドに渡すことで、高さ 376 dp を使用します。- 表示されるカルーセル アイテムのインデックスを示す整数値で呼び出されるラムダ。
featuredMovieList
変数と指定されたインデックス値からMovie
オブジェクトを取得します。CarouselSlide
Composable
関数をCarousel
Composable
関数に追加します。- 映画のタイトルを表示するには、
CarouselSlide
Composable
関数にText
Composable
関数を追加します。
CatalogBrowser.kt
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.TvLazyRow
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.Carousel
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import com.example.tvcomposeintroduction.data.Movie
import com.example.tvcomposeintroduction.ui.components.MovieCard
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsState()
TvLazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
item {
val featuredMovieList by catalogBrowserViewModel.featuredMovieList.collectAsState()
Carousel(
slideCount = featuredMovieList.size,
modifier = Modifier
.fillMaxWidth()
.height(376.dp)
) { indexOfCarouselSlide ->
val featuredMovie =
featuredMovieList[indexOfCarouselSlide]
CarouselSlide {
Text(text = featuredMovie.title)
}
}
}
items(categoryList) { category ->
Text(text = category.name)
TvLazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie, onClick = { onMovieSelected(movie) })
}
}
}
}
}
背景画像を表示する
CarouselSlide
Composable
関数は、別のラムダを使用して、CarouselSlide
Composable
関数の背景をどのように表示するかを指定できます。
背景画像を表示する手順は次のとおりです。
background
パラメータを使用してラムダをCarouselSlide
Composable
関数に渡します。AsyncImage
Composable
関数を呼び出して、Movie
オブジェクトに関連付けられた背景画像をCarouselSlide
Composable
関数の背景に読み込みます。- 視認性を高めるため、
CarouselSlide
Composable
関数内のText
Composable
関数の位置とテキスト スタイルを更新しました。 - レイアウト シフトを避けるため、プレースホルダを
AsyncImage
Composable
関数に設定します。スターター コードには、R.drawable.placeholder
で参照できるドローアブルとしてプレースホルダがあります。
CatalogBrowser.kt
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.TvLazyRow
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.Carousel
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import coil.compose.AsyncImage
import com.example.tvcomposeintroduction.R
import com.example.tvcomposeintroduction.data.Movie
import com.example.tvcomposeintroduction.ui.components.MovieCard
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsState()
TvLazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
item {
val featuredMovieList by catalogBrowserViewModel.featuredMovieList.collectAsState()
Carousel(
slideCount = featuredMovieList.size,
modifier = Modifier
.fillMaxWidth()
.height(376.dp),
) { indexOfCarouselItem ->
val featuredMovie = featuredMovieList[indexOfCarouselItem]
CarouselSlide(
background = {
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)
TvLazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie, onClick = { onMovieSelected(movie) })
}
}
}
}
}
詳細画面への画面遷移を追加する
ユーザーに CarouselSlide
Composable
関数のクリックを許可できます。
詳細画面のカルーセル アイテムでユーザーが映画の詳細を確認できるようにするには、次の手順を行います。
modifier
パラメータを通じて、Modifier.clickable
メソッドの戻り値をCarouselSlide
Composable
関数に渡します。Modifier.clickable
メソッドに渡されるラムダ内の可視CarouselSlide
のComposable
関数に対して、Movie
オブジェクトを指定してonMovieSelected
関数を呼び出します。
CatalogBrowser.kt
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.TvLazyRow
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.Carousel
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import coil.compose.AsyncImage
import com.example.tvcomposeintroduction.R
import com.example.tvcomposeintroduction.data.Movie
import com.example.tvcomposeintroduction.ui.components.MovieCard
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsState()
TvLazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
item {
val featuredMovieList by catalogBrowserViewModel.featuredMovieList.collectAsState()
Carousel(
slideCount = featuredMovieList.size,
modifier = Modifier
.fillMaxWidth()
.height(376.dp),
) { indexOfCarouselItem ->
val featuredMovie = featuredMovieList[indexOfCarouselItem]
CarouselSlide(
background = {
AsyncImage(
model = featuredMovie.backgroundImageUrl,
contentDescription = null,
placeholder = painterResource(
id = R.drawable.placeholder
),
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize(),
)
},
modifier = Modifier.clickable { onMovieSelected(featuredMovie) }
) {
Text(text = featuredMovie.title)
}
}
}
items(categoryList) { category ->
Text(text = category.name)
TvLazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie, onClick = { onMovieSelected(movie) })
}
}
}
}
}
7. 解答コードを取得する
この Codelab の解答コードをダウンロードするには、次のいずれかを行います。
- 次のボタンをクリックして 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 の基本を習得しました。
- TvLazyColumn と TvLazyLow を組み合わせてコンテンツ リストを表示する画面の実装方法。
- コンテンツの詳細を表示する基本的な画面の実装。
- 2 つの画面間の画面遷移を追加する方法。