テレビで使用するメディアアプリでは、ユーザーが提供コンテンツをブラウズして選び、再生を開始できるようにする必要があります。このタイプのアプリのコンテンツ ブラウジングに関するユーザー エクスペリエンスは、直観的で、目を楽しませる魅力的なものである必要があります。
カタログ ブラウザは通常、複数のセクションで構成され、各セクションにはメディア コンテンツのリストが含まれています。メディア カタログのセクションの例としては、再生リスト、注目のコンテンツ、おすすめカテゴリなどがあります。
Compose for TV が提供する関数を使用して、アプリのメディア カタログから音楽や動画を閲覧するためのユーザー インターフェースを実装します。
カタログのコンポーザブル関数を作成する
ディスプレイに表示されるものはすべて、Compose for TV のコンポーズ可能な関数として実装されます。まず、メディア カタログ ブラウザのコンポーザブル関数を定義します。
@Composable fun CatalogBrowser( featuredContentList: List<Movie>, sectionList: List<Section>, modifier: Modifier = Modifier, onItemSelected: (Movie) -> Unit = {}, ) { // ToDo: add implementation }
CatalogBrowser は、メディア カタログ ブラウザを実装するコンポーズ可能な関数です。この関数は次の引数を取ります。
- 注目のコンテンツのリスト。
- セクションのリスト。
- Modifier オブジェクト。
- 画面遷移をトリガーするコールバック関数。
UI 要素を設定する
Compose for TV には、多数のアイテム(または長さが不明なリスト)を表示するコンポーネントである遅延リストが用意されています。セクションを縦方向に配置するには、LazyColumn を呼び出します。LazyColumn は、アイテムのコンテンツを定義する DSL を提供する LazyListScope.() -> Unit ブロックを提供します。次の例では、各セクションが縦方向のリストに配置され、セクション間のギャップは 16 dp になっています。
@Composable fun CatalogBrowser( featuredContentList: List<Movie>, sectionList: List<Section>, modifier: Modifier = Modifier, onItemSelected: (Movie) -> Unit = {}, ) { LazyColumn( modifier = modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(16.dp) ) { items(sectionList.size) { index -> val section = sectionList[index] SectionRow(section, onItemSelected = onItemSelected) } } }
この例では、SectionRow コンポーズ可能な関数がセクションの表示方法を定義しています。次の関数では、LazyRow は、この LazyColumn の水平バージョンが、提供された DSL を呼び出すことで LazyListScope.() -> Unit ブロックを含む水平リストを定義するために同様に使用される方法を示しています。
@Composable fun SectionRow( section: Section, modifier: Modifier = Modifier, onItemSelected: (Movie) -> Unit = {}, ) { Text( text = section.title, style = MaterialTheme.typography.headlineSmall, ) MovieCatalog( section.movieList, onClick = { movie -> onItemSelected(movie) }, modifier ) }
@Composable fun MovieCatalog( movies: List<Movie>, onClick: (Movie) -> Unit, modifier: Modifier = Modifier, ) { LazyRow( modifier = modifier, horizontalArrangement = Arrangement.spacedBy(8.dp) ) { items(movies.size) { index -> val movie = movies[index] MovieCard( movie = movie, onClick = { onClick(movie) } ) } } }
SectionRow コンポーザブルでは、Text コンポーネントが使用されます。マテリアル デザインで定義されたテキストなどのコンポーネントは、tv-material ライブラリで提供されます。MaterialTheme オブジェクトを参照することで、マテリアル デザインで定義されているテキストのスタイルを変更できます。このオブジェクトも tv-material ライブラリによって提供されます。Card は tv-material ライブラリの一部です。MovieCard は、次のスニペットで定義されたカタログで各映画データがどのようにレンダリングされるかを定義します。
@OptIn(ExperimentalMaterial3Api::class) @Composable fun MovieCard( movie: Movie, modifier: Modifier = Modifier, onClick: () -> Unit = {} ) { Card( modifier = modifier, onClick = onClick ) { AsyncImage( model = movie.thumbnailUrl, contentDescription = movie.title, ) } }
注目のコンテンツをハイライト表示する
前述の例では、すべての映画が均等に表示されます。面積は同じで、見た目の違いはありません。Carousel を使用して、一部をハイライト表示できます。
カルーセルは、スライド、フェード、移動して表示できる一連のアイテムで情報を表示します。このコンポーネントは、新しく利用可能になった映画やテレビ番組の新エピソードなど、注目のコンテンツをハイライト表示するために使用します。
Carousel では、カルーセルに表示するアイテムの数と各アイテムの描画方法を少なくとも指定する必要があります。最初の 1 つは itemCount で指定できます。2 つ目はラムダとして渡すことができます。表示されたアイテムのインデックス番号がラムダに渡されます。表示されるアイテムは、指定されたインデックス値で決定できます。
@OptIn(ExperimentalTvMaterial3Api::class) @Composable fun FeaturedCarousel( featuredContentList: List<Movie>, modifier: Modifier = Modifier, ) { Carousel( itemCount = featuredContentList.size, modifier = modifier, ) { index -> val content = featuredContentList[index] Box { AsyncImage( model = content.backgroundImageUrl, contentDescription = content.description, placeholder = painterResource( id = R.drawable.movie_placeholder ), contentScale = ContentScale.Crop, modifier = Modifier.fillMaxSize() ) Text(text = content.title) } } }
Carousel は、TvLazyColumn などの遅延リストの項目にできます。次のスニペットは、すべての SectionRow コンポーザブルの上に FeaturedCarousel コンポーザブルを表示する方法を示しています。
@OptIn(ExperimentalTvMaterial3Api::class) @Composable fun CatalogBrowser( featuredContentList: List<Movie>, sectionList: List<Section>, modifier: Modifier = Modifier, onItemSelected: (Movie) -> Unit = {}, ) { LazyColumn( modifier = modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(16.dp) ) { item { FeaturedCarousel(featuredContentList) } items(sectionList) { section -> SectionRow(section, onItemSelected = onItemSelected) } } }