I'm writing a TV app using Jetpack Compose (1.0.0-alpha06). The main screen of my app is a pretty basic list of shelves/rows implemented using a TvLazyColumn
with several TvLazyRows
. When I navigate to child/detail screen and pop back to the main screen, focus doesn't seem to be on any item in particular. If I push one of the d-pad buttons it'll set focus to an item and I can resume as normal. However, this obviously isn't the best experience for my users.
I tried saving the list state via rememberTvLazyListState
variables to the column and rows but it didn't make a difference. I also tried explicitly setting unique keys on the column/rows items
call but it also didn't fix it.
I recreated it in a simple app:
Here's the code for the app above:
package com.example.myapplication
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.fragment.app.FragmentActivity
import androidx.navigation.NavController
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.TvLazyRow
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.Card
import androidx.tv.material3.CardDefaults
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
class MainActivity : FragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
NavGraph()
}
}
}
@Composable
fun NavGraph(
modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController()
) {
NavHost(
modifier = modifier,
navController = navController,
startDestination = "main"
) {
composable("main") {
Main(navController)
}
composable("detail/{item}") {
Detail(
item = it.arguments?.getString("item") ?: "<null>",
navController = navController
)
}
}
}
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun Main(navController: NavController = rememberNavController()) {
TvLazyColumn(
modifier = Modifier
.fillMaxSize(),
contentPadding = PaddingValues(horizontal = 20.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
items((1..10).toList()) { row ->
Text(
"Row $row",
color = Color.White
)
Spacer(modifier = Modifier.height(5.dp))
TvLazyRow(
horizontalArrangement = Arrangement.spacedBy(10.dp)
) {
items((1..10).toList()) { col ->
val item = "Item $row.$col"
Card(
onClick = { navController.navigate("detail/$item") },
colors = CardDefaults.colors(containerColor = Color.Red),
modifier = Modifier
.size(100.dp)
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(item,
color = Color.White,
modifier = Modifier
.align(Alignment.Center)
)
}
}
}
}
}
}
}
@Preview(device = "id:tv_1080p")
@Composable
fun MainPreview() {
Main()
}
@Composable
fun Detail(item: String,
navController: NavController = rememberNavController()
) {
Box(modifier = Modifier.fillMaxSize()) {
Text("You clicked item $item",
color = Color.White,
fontSize = 30.sp,
modifier = Modifier.align(Alignment.Center)
)
}
}
@Preview(device = "id:tv_1080p")
@Composable
fun DetailPreview() {
Detail("Item 1.1")
}