You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AndroidTV FocusRestorer移除焦点节点后无法回退焦点的问题咨询

临时解决方案:Android TV LazyRow焦点丢失回退异常问题

针对你遇到的LazyRow移除获焦节点后,默认focusRestorer未触发指定回退焦点的问题,以下是几个可落地的临时处理方案:

方案1:手动追踪焦点位置并在数据更新后重定向

  • 提前记录当前获焦卡片的行索引和列索引(可存在ViewModel或remember状态中)
  • 在LazyRow数据更新完成后,检查原焦点位置是否还在新数据范围内:
    • 若存在,通过对应位置的FocusRequester主动请求焦点
    • 若不存在,直接请求预设的回退焦点(比如该行首个可见项)
  • 核心代码示例:
// 保存当前焦点的行、列索引
var focusedRow by remember { mutableStateOf(0) }
var focusedCol by remember { mutableStateOf(0) }

// 卡片项中监听焦点变化
Card(
    modifier = Modifier
        .onFocusChanged {
            if (it.isFocused) {
                focusedRow = currentRowIdx
                focusedCol = currentColIdx
            }
        }
) { /* 卡片内容 */ }

// 数据更新后触发焦点调整
LaunchedEffect(swimlaneData) {
    val targetSwimlane = swimlaneData.getOrNull(focusedRow) ?: swimlaneData.first()
    val targetIdx = if (focusedCol < targetSwimlane.size) focusedCol else 0
    // 假设focusRequesters是按行存储的FocusRequester列表
    focusRequesters[focusedRow][targetIdx].requestFocus()
}

方案2:自定义焦点恢复逻辑,替代默认focusRestorer

  • 移除LazyRow上默认的focusRestorer,改用onFocusEvent监听焦点移除事件
  • 当检测到焦点因节点被移除而丢失时,主动触发回退焦点请求:
val fallbackRequester = remember { FocusRequester() }

LazyRow(
    modifier = Modifier
        .onFocusEvent { event ->
            // 监听焦点因节点被移除而丢失的事件
            if (event.type == FocusEventType.Unfocus && event.cause == FocusEventCause.Removal) {
                fallbackRequester.requestFocus()
            }
        }
) {
    items(swimlaneItems) { item ->
        val isFirstItem = /* 判断是否为该行首个可见项 */
        if (item.isPlaceholder) {
            Placeholder(modifier = Modifier.focusable())
        } else {
            Card(
                modifier = Modifier
                    .then(if (isFirstItem) Modifier.focusRequester(fallbackRequester) else Modifier)
                    .focusable()
            ) { /* 卡片内容 */ }
        }
    }
}

方案3:复用占位符与真实卡片的FocusRequester

  • 为每个列表位置创建固定的FocusRequester,不管显示占位符还是真实卡片都复用同一个
  • 当数据加载完成替换占位符时,焦点会自动保留在原位置的真实卡片上:
// 根据列表大小初始化固定的FocusRequester列表
val requesters = remember(swimlaneItems.size) {
    List(swimlaneItems.size) { FocusRequester() }
}

LazyRow {
    itemsIndexed(swimlaneItems) { idx, item ->
        if (item.isLoading) {
            Placeholder(
                modifier = Modifier
                    .focusRequester(requesters[idx])
                    .focusable()
            )
        } else {
            Card(
                modifier = Modifier
                    .focusRequester(requesters[idx])
                    .focusable()
            ) { /* 卡片内容 */ }
        }
    }
}

内容的提问来源于stack exchange,提问作者Da_Shizzle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 13:44:54