テレビアプリの場合、ブラウジング エクスペリエンスは効率的なフォーカスベースのナビゲーションに依存します。標準の Compose Foundation レイジー レイアウトを使用すると、フォーカス駆動型スクロールを自動的に処理してアクティブなアイテムをビュー内に維持する、パフォーマンスの高い縦方向と横方向のリストを作成できます。
テレビ向けに最適化されたデフォルトのスクロール動作
Compose Foundation 1.7.0 以降では、標準の遅延レイアウト(LazyRow や LazyColumn など)にフォーカス位置指定機能の組み込みサポートが含まれています。これは、ユーザーが注目しているアイテムを直感的に表示し続けるのに役立つため、テレビアプリのカタログを作成するうえで推奨される方法です。
基本的なスクロール可能なリストを実装するには、標準の遅延コンポーネントを使用します。これらのコンポーネントは、D-pad ナビゲーションを自動的に処理し、フォーカスされたアイテムをビューに表示します。
import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items @Composable fun MovieCatalog(movies: List<Movie>) { LazyRow { items(movies) { movie -> MovieCard( movie = movie, onClick = { /* Handle click */ } ) } } }
BringIntoViewSpec でスクロールの動作をカスタマイズする
デザインで特定の「ピボット」ポイント(たとえば、フォーカスされたアイテムを左端から 30% の位置に保つ)が必要な場合は、BringIntoViewSpec を使用してスクロール動作をカスタマイズできます。これにより、フォーカスされたアイテムに合わせてビューポートをスクロールする方法を正確に定義できるようになり、以前の pivotOffsets 機能が置き換えられます。
1. カスタム BringIntoViewSpec を定義する
次のヘルパー コンポーザブルを使用すると、親と子の割合に基づいて「ピボット」を定義できます。parentFraction は、コンテナ内のアイテムの着地点を決定し、childFraction は、そのポイントに揃えるアイテムの部分を決定します。
@OptIn(ExperimentalFoundationApi::class) @Composable fun PositionFocusedItemInLazyLayout( parentFraction: Float = 0.3f, childFraction: Float = 0f, content: @Composable () -> Unit, ) { val bringIntoViewSpec = remember(parentFraction, childFraction) { object : BringIntoViewSpec { override fun calculateScrollDistance( offset: Float, // Item's initial position size: Float, // Item's size containerSize: Float // Container's size ): Float { // Calculate the offset position of the item's leading edge. val initialTargetForLeadingEdge = parentFraction * containerSize - (childFraction * size) // If the item fits in the container, and scrolling would cause // its trailing edge to be clipped, adjust targetForLeadingEdge // to prevent over-scrolling near the end of list. val targetForLeadingEdge = if (size <= containerSize && (containerSize - initialTargetForLeadingEdge) < size) { // If clipped, align the item's trailing edge with the // container's trailing edge. containerSize - size } else { initialTargetForLeadingEdge } // Return scroll distance relative to initial item position. return offset - targetForLeadingEdge } } } // Apply the spec to all scrollables in the hierarchy CompositionLocalProvider( LocalBringIntoViewSpec provides bringIntoViewSpec, content = content, ) }
2. カスタム仕様を適用する
レイアウトをヘルパーでラップして、位置合わせを適用します。これは、カタログのさまざまな行にわたって「一貫したフォーカス線」を作成する場合に便利です。
PositionFocusedItemInLazyLayout( parentFraction = 0.3f, // Pivot 30% from the edge childFraction = 0.5f // Center of the item aligns with the pivot ) { LazyColumn { items(sectionList) { section -> // This row and its items will respect the 30% pivot LazyRow { /* ... */ } } } }
3. 特定のネストされたレイアウトをオプトアウトする
カスタム ピボットではなく標準のスクロール動作を使用する必要がある特定のネストされたレイアウトがある場合は、DefaultBringIntoViewSpec を指定します。
private val DefaultBringIntoViewSpec = object : BringIntoViewSpec {} PositionFocusedItemInLazyLayout { LazyColumn { item { // This row will ignore the custom pivot and use default behavior CompositionLocalProvider(LocalBringIntoViewSpec provides DefaultBringIntoViewSpec) { LazyRow { /* ... */ } } } } }
実際には、空の BringIntoViewSpec を渡すことで、フレームワークのデフォルトの動作が引き継がれます。
TV Foundation から Compose Foundation への移行
androidx.tv.foundation のテレビ専用の遅延レイアウトは、標準の Compose Foundation レイアウトに置き換えられました。
依存関係の更新
build.gradle が次のバージョン 1.7.0 以降を使用していることを確認します。
androidx.compose.foundationandroidx.compose.runtime
コンポーネントのマッピング
移行するには、インポートを更新し、コンポーネントから Tv 接頭辞を削除します。
| 非推奨のテレビ コンポーネント | Compose Foundation の代替 |
|---|---|
| TvLazyRow | LazyRow |
| TvLazyColumn | LazyColumn |
| TvLazyHorizontalGrid | LazyHorizontalGrid |
| TvLazyVerticalGrid | LazyVerticalGrid |
| pivotOffsets | BringIntoViewSpec(LocalBringIntoViewSpec 経由) |