Per le app TV, l'esperienza di navigazione si basa su una navigazione efficiente basata sulla messa a fuoco. Utilizzando i layout pigri standard di Compose Foundation, puoi creare elenchi verticali e orizzontali efficienti che gestiscono automaticamente lo scorrimento basato sullo stato attivo per mantenere in vista gli elementi attivi.
Comportamento di scorrimento predefinito ottimizzato per la TV
A partire da Compose Foundation 1.7.0, i layout pigri standard (come LazyRow
e LazyColumn) includono il supporto integrato per le funzionalità di posizionamento della messa a fuoco. Questo è il modo consigliato per creare cataloghi per le app TV, in quanto consente di mantenere visibili e posizionati in modo intuitivo per l'utente gli elementi in primo piano.
Per implementare un elenco di base scorrevole, utilizza i componenti lazy standard. Questi componenti gestiscono automaticamente la navigazione con il D-pad e portano l'elemento selezionato in primo piano.
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 */ }
)
}
}
}
Personalizza il comportamento di scorrimento con BringIntoViewSpec
Se il tuo design richiede un punto di "pivot" specifico (ad esempio, mantenere l'elemento
focalizzato esattamente al 30% dal bordo sinistro), puoi personalizzare lo scorrimento
utilizzando un BringIntoViewSpec. Questa funzionalità sostituisce la precedente pivotOffsets
consentendoti di definire esattamente come deve scorrere la finestra
per adattarsi a un elemento selezionato.
1. Definisci un BringIntoViewSpec personalizzato
Il seguente composable helper ti consente di definire un "pivot" in base alle frazioni padre e figlio. parentFraction determina il punto del contenitore in cui deve essere posizionato l'elemento, mentre childFraction determina la parte dell'elemento che si allinea a quel 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. Applica la specifica personalizzata
Racchiudi i layout con l'helper per applicare il posizionamento. Questa funzionalità è utile per creare una "linea di messa a fuoco coerente" in diverse righe del catalogo.
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. Disattivazione per layout nidificati specifici
Se hai un layout nidificato specifico che deve utilizzare il comportamento di scorrimento standard
anziché il pivot personalizzato, fornisci 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 { ... }
}
}
}
}
In effetti, il passaggio di un BringIntoViewSpec vuoto consente di attivare il comportamento predefinito del framework.
Migrazione da TV Foundation a Compose Foundation
I layout pigri specifici per la TV in androidx.tv.foundation sono ritirati a favore
dei layout standard di Compose Foundation.
Aggiornamenti delle dipendenze
Verifica che build.gradle utilizzi la versione 1.7.0 o successive per:
androidx.compose.foundationandroidx.compose.runtime
Mappatura dei componenti
Per eseguire la migrazione, aggiorna le importazioni e rimuovi il prefisso Tv dai componenti:
| Componente TV ritirato | Compose Foundation replacement |
|---|---|
| TvLazyRow | LazyRow |
| TvLazyColumn | LazyColumn |
| TvLazyHorizontalGrid | LazyHorizontalGrid |
| TvLazyVerticalGrid | LazyVerticalGrid |
| pivotOffsets | BringIntoViewSpec (tramite LocalBringIntoViewSpec) |