En el caso de las apps para TVs, la experiencia de navegación se basa en una navegación eficiente basada en el enfoque. Con los diseños perezosos estándar de Compose Foundation, puedes crear listas verticales y horizontales de alto rendimiento que controlan automáticamente el desplazamiento controlado por el enfoque para mantener los elementos activos a la vista.
Comportamiento de desplazamiento predeterminado optimizado para la TV
A partir de Compose Foundation 1.7.0, los diseños diferidos estándar (como LazyRow y LazyColumn) incluyen compatibilidad integrada con las funciones de posicionamiento del enfoque. Esta es la forma recomendada de crear catálogos para apps de TV, ya que ayuda a que los elementos enfocados permanezcan visibles y se posicionen de forma intuitiva para el usuario.
Para implementar una lista desplazable básica, usa los componentes lazy estándar. Estos componentes controlan automáticamente la navegación con el pad direccional y muestran el elemento enfocado.
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 */ }
)
}
}
}
Personaliza el comportamiento de desplazamiento con BringIntoViewSpec
Si tu diseño requiere un punto de "pivote" específico (por ejemplo, mantener el elemento enfocado exactamente a un 30% del borde izquierdo), puedes personalizar el comportamiento de desplazamiento con un BringIntoViewSpec. Esto reemplaza la funcionalidad anterior de pivotOffsets, ya que te permite definir exactamente cómo debe desplazarse el viewport para adaptarse a un elemento enfocado.
1. Cómo definir un BringIntoViewSpec personalizado
El siguiente elemento componible auxiliar te permite definir un "pivote" basado en fracciones secundarias y principales. El parentFraction determina en qué lugar del contenedor debe colocarse el elemento, y el childFraction determina qué parte del elemento se alinea con ese punto.
@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. Aplica la especificación personalizada
Encapsula tus diseños con el asistente para aplicar el posicionamiento. Esto es útil para crear una "línea de enfoque coherente" en diferentes filas de tu catálogo.
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. Cómo inhabilitar diseños anidados específicos
Si tienes un diseño anidado específico que debería usar el comportamiento de desplazamiento estándar en lugar de tu pivote personalizado, proporciona 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 { ... }
}
}
}
}
En efecto, pasar un BringIntoViewSpec vacío permite que se haga cargo el comportamiento predeterminado del framework.
Migración de TV Foundation a Compose Foundation
Los diseños diferidos específicos para TVs en androidx.tv.foundation quedaron obsoletos en favor de los diseños estándar de Compose Foundation.
Actualizaciones de dependencias
Verifica que tu build.gradle use la versión 1.7.0 o una posterior para lo siguiente:
androidx.compose.foundationandroidx.compose.runtime
Asignación de componentes
Para migrar, actualiza tus importaciones y quita el prefijo Tv de tus componentes:
| Componente de TV obsoleto | Reemplazo de Compose Foundation |
|---|---|
| TvLazyRow | LazyRow |
| TvLazyColumn | LazyColumn |
| TvLazyHorizontalGrid | LazyHorizontalGrid |
| TvLazyVerticalGrid | LazyVerticalGrid |
| pivotOffsets | BringIntoViewSpec (a través de LocalBringIntoViewSpec) |