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

Android TV Jetpack Compose焦点未清除:列表与按钮焦点共存问题

问题修复方案

核心问题分析

  1. onKeyEvent返回false,导致DPAD_UP事件会继续被TvLazyColumn处理,焦点无法彻底转移
  2. 手动维护的watchNowBtnFocus布尔值未与Compose焦点系统联动,仅视觉上变化,实际焦点仍保留在列表
  3. 焦点转移的时机与操作顺序存在问题,未彻底完成列表焦点释放与按钮焦点捕获的流程

具体修复步骤

1. 修正按键事件的返回逻辑

在第一行按上键的分支中,处理完状态更新后返回true,阻止事件继续传递给列表:

TvLazyColumn(
    state = listState,
    pivotOffsets = PivotOffsets(0.15F),
    modifier = Modifier
        .focusRequester(setFocusContinueWatch)
        .onKeyEvent {
            if (it.nativeKeyEvent.action == KeyEvent.ACTION_DOWN) {
                when (it.nativeKeyEvent.keyCode) {
                    KeyEvent.KEYCODE_DPAD_UP -> {
                        if (selectedRow > 0) {
                            selectedRow--
                            isUpFromList = false
                            false // 让列表处理正常上移逻辑
                        } else {
                            isUpFromList = true
                            isFocusOnListing = false
                            true // 消费事件,阻止列表继续处理
                        }
                    }
                    KeyEvent.KEYCODE_DPAD_DOWN -> {
                        if (selectedRow < sizeOfRows!!) {
                            selectedRow++
                            isFocusOnListing = true
                            isUpFromList = false
                            false // 让列表处理正常下移逻辑
                        } else {
                            false
                        }
                    }
                    else -> false
                }
            } else {
                false
            }
        }
)

2. 优化焦点转移逻辑,移除自定义焦点状态

用Compose原生FocusRequester管理按钮焦点,确保焦点系统正确联动:

// 定义按钮的焦点请求器
val watchNowFocusRequester = remember { FocusRequester() }

// 调整LaunchedEffect触发条件,监听isUpFromList
LaunchedEffect(isUpFromList) {
    if (isUpFromList) {
        // 释放列表焦点
        setFocusContinueWatch.freeFocus()
        // 等待一帧确保焦点释放完成,再请求按钮焦点
        withFrameMillis {
            watchNowFocusRequester.requestFocus()
        }
        // 重置标记
        isUpFromList = false
    }
}

// WatchNow按钮的Modifier配置
Button(
    onClick = { /* 点击逻辑 */ },
    modifier = Modifier
        .focusRequester(watchNowFocusRequester)
        .focusable()
        .visible(!isFocusOnListing)
) {
    Text("Watch Now")
}

3. 绑定列表焦点状态与isFocusOnListing

在TvLazyColumn的Modifier中,根据isFocusOnListing控制列表是否可获取焦点,避免焦点残留:

TvLazyColumn(
    // ... 其他参数
    modifier = Modifier
        .focusRequester(setFocusContinueWatch)
        .focusable(isFocusOnListing) // isFocusOnListing为false时,列表不可获取焦点
        .onKeyEvent { /* ... 按键逻辑 ... */ }
)

额外注意事项

  • 避免混用freeFocus()与captureFocus(),优先使用requestFocus()更符合Compose焦点系统设计
  • 焦点操作配合withFrameMillis延迟执行,避免状态更新与焦点转移的竞态问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 22:48:11