Plo*_*ial 5 android kotlin android-tv android-jetpack-compose android-jetpack-compose-tv
我在 TvLazyColumn 中有 TvLazyRows。当我导航到所有列表的末尾(位置 [20,20])导航到下一个屏幕并返回时,焦点将恢复到第一个可见位置 [15,1],而不是我之前所在的位置 [20,20] ]。如何将焦点恢复到某个特定位置?
class MainActivity : ComponentActivity() {
private val rowItems = (0..20).toList()
private val rows = (0..20).toList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
MyAppNavHost(navController = navController)
}
}
@Composable
fun List(navController: NavController) {
val fr = remember {
FocusRequester()
}
TvLazyColumn( modifier = Modifier
.focusRequester(fr)
.fillMaxSize()
,
verticalArrangement = Arrangement.spacedBy(16.dp),
pivotOffsets = PivotOffsets(parentFraction = 0.05f),
) {
items(rows.size) { rowPos ->
Column() {
Text(text = "Row $rowPos")
TvLazyRow(
modifier = Modifier
.height(70.dp),
horizontalArrangement = Arrangement.spacedBy(16.dp),
pivotOffsets = PivotOffsets(parentFraction = 0.0f),
) {
items(rowItems.size) { itemPos ->
var color by remember {
mutableStateOf(Color.Green)
}
Box(
Modifier
.width(100.dp)
.height(50.dp)
.onFocusChanged {
color = if (it.hasFocus) {
Color.Red
} else {
Color.Green
}
}
.background(color)
.clickable {
navController.navigate("details")
}
) {
Text(text = "Item ${itemPos.toString()}", Modifier.align(Alignment.Center))
}
}
}
}
}
}
LaunchedEffect(true) {
fr.requestFocus()
}
}
@Composable
fun MyAppNavHost(
navController: NavHostController = rememberNavController(),
startDestination: String = "list"
) {
NavHost(
navController = navController,
startDestination = startDestination
) {
composable("details") {
Details()
}
composable("list") { List(navController) }
}
}
@Composable
fun Details() {
Box(
Modifier
.background(Color.Blue)
.fillMaxSize()) {
Text("Second Screen", Modifier.align(Alignment.Center), fontSize = 48.sp)
}
}
}
Run Code Online (Sandbox Code Playgroud)
版本
dependencies {
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.activity:activity-compose:1.7.1'
implementation platform('androidx.compose:compose-bom:2022.10.00')
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00')
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
debugImplementation 'androidx.compose.ui:ui-tooling'
debugImplementation 'androidx.compose.ui:ui-test-manifest'
// Compose for TV dependencies
def tvCompose = '1.0.0-alpha06'
implementation "androidx.tv:tv-foundation:$tvCompose"
implementation "androidx.tv:tv-material:$tvCompose"
def nav_version = "2.5.3"
implementation "androidx.navigation:navigation-compose:$nav_version"
}
Run Code Online (Sandbox Code Playgroud)
我尝试将 FocusRequestor 传递给列表中的每个可聚焦元素。在这种情况下,我能够恢复注意力。但是对于列表中的大量元素,它开始因 OutOfMemmoryError 而崩溃。所以我需要另一种解决方案。
小智 4
在 Jetpack Compose 中,导航在设计上是无状态的,这意味着默认情况下不保留焦点状态。为了实现这一点,我们必须自己维护状态(项目的位置)。
下面是一个建议的解决方案,您可以将其集成到您的代码中。请注意,此解决方案的工作假设是列表中的项目不会动态更改。如果他们这样做,你可能需要稍微调整一下逻辑:
private var lastFocusedItem by rememberSaveable{ mutableStateOf(Pair(0, 0)) }
Run Code Online (Sandbox Code Playgroud)
lastFocusedItem
。.onFocusChanged { focusState ->
if (focusState.hasFocus) {
lastFocusedItem = Pair(rowPos, itemPos)
}
...
}
Run Code Online (Sandbox Code Playgroud)
LaunchedEffect(true) {
// Request focus to the last focused item
focusRequesters[lastFocusedItem]?.requestFocus()
}
Run Code Online (Sandbox Code Playgroud)
为了实现最后一点,我们需要有 s 的映射FocusRequester
。我们应该使用一个映射,其中键作为项目位置(rowPos,itemPos),值作为FocusRequester
s。
这是代码的更新部分,用于维护和恢复上次导航项目的焦点。
这是一个两步过程:
FocusRequester
值。使用 RememberSaveable 在屏幕导航期间保留值。FocusRequester
每个项目的 a 并将其添加到focusRequesters
地图中。您更新后的List
可组合项可能如下所示:
@Composable
fun List(navController: NavController) {
val focusRequesters = remember { mutableMapOf<Pair<Int, Int>, FocusRequester>() }
var lastFocusedItem by rememberSaveable{ mutableStateOf(Pair(0, 0)) }
TvLazyColumn(
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(16.dp),
pivotOffsets = PivotOffsets(parentFraction = 0.05f),
) {
items(rows.size) { rowPos ->
Column() {
Text(text = "Row $rowPos")
TvLazyRow(
modifier = Modifier
.height(70.dp),
horizontalArrangement = Arrangement.spacedBy(16.dp),
pivotOffsets = PivotOffsets(parentFraction = 0.0f),
) {
items(rowItems.size) { itemPos ->
var color by remember { mutableStateOf(Color.Green) }
val fr = remember { FocusRequester() }
focusRequesters[Pair(rowPos, itemPos)] = fr
Box(
Modifier
.width(100.dp)
.height(50.dp)
.focusRequester(fr)
.onFocusChanged {
color = if (it.hasFocus) {
lastFocusedItem = Pair(rowPos, itemPos)
Color.Red
} else {
Color.Green
}
}
.background(color)
.clickable {
navController.navigate("details")
}
) {
Text(text = "Item ${itemPos.toString()}", Modifier.align(Alignment.Center))
}
}
}
}
}
}
LaunchedEffect(true) {
focusRequesters[lastFocusedItem]?.requestFocus()
}
}
Run Code Online (Sandbox Code Playgroud)
附言。拥有可组合的方法是一个坏主意。可组合项应该是没有副作用的纯函数。
归档时间: |
|
查看次数: |
1846 次 |
最近记录: |