テレビで動作するメディアアプリでは、ユーザーがコンテンツをブラウジングして選択し、再生を開始できるようにする必要があります。このタイプのアプリのコンテンツ ブラウジング エクスペリエンスは、直感的で、視覚的に魅力的で、魅力的なものである必要があります。
カタログ ブラウザは通常、複数のセクションで構成され、各セクションにメディア コンテンツのリストがあります。メディア カタログのセクションの例としては、プレイリスト、注目のコンテンツ、おすすめのカテゴリなどがあります。
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 には、多数のアイテム(または長さが不明なリスト)を表示するコンポーネントである Lazy リストが用意されています。LazyColumn を呼び出して、セクションを縦方向に配置します。LazyColumn には LazyListScope.() -> Unit ブロックが用意されており、アイテムのコンテンツを定義するための DSL が提供されています。次の例では、各セクションが縦方向のリストに配置され、セクション間に 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 は、LazyColumn などの遅延リストのアイテムにできます。次のスニペットは、すべての 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) } } }