android Jetpack合成RequestFocus仅工作一次

cpjpxq1n  于 2023-01-24  发布在  Android
关注(0)|答案(1)|浏览(141)

我正在构建一个场景,点击一个按钮会生成一个新的屏幕标题和内容。根据可访问性要求,点击一个按钮会将TalkBack焦点放在屏幕标题上,这样用户就可以听到新内容的内容。
屏幕应该是这样的:

Column(){
    Title()
    Content()
    RefreshContentButton()
}

我使用了一个FocusRequester示例来请求按钮被点击时的焦点,这是第一次**很好地工作,当用户返回到刷新按钮并点击它时,焦点不会改变。
我已经设置了一个显示该问题的示例。在启用TalkBack的情况下,第一次单击按钮成功地将焦点放在相应的Focusable上,第二次单击没有任何操作。但是,如果交替单击按钮,则一切正常。

class MainActivity : ComponentActivity() {
    @OptIn(ExperimentalComposeUiApi::class)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val (ref1, ref2) = remember { FocusRequester.createRefs() }
            Column(
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.SpaceBetween,
            ) {
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceAround
                ) {
                    Focusable("Focusable #1", ref1)
                    Focusable("Focusable #2", ref2)
                }
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceAround
                ) {
                    Button(
                        onClick = {
                            ref1.requestFocus()
                        }) {
                        Text(text = "Focus on #1")
                    }
                    Button(
                        onClick = {
                            ref2.requestFocus()
                        }) {
                        Text(text = "Focus on #2")
                    }
                }
            }
        }
    }
}

@Composable
fun Focusable(text: String, focusRequester: FocusRequester) {
    Box(
        modifier = Modifier.height(100.dp),
        contentAlignment = Alignment.Center,
    ) {
        Text(text = text, modifier = Modifier
            .focusRequester(focusRequester)
            .focusable(true)
            .focusProperties {
                canFocus = true
            }
            .focusTarget())
    }
}
deyfvvtc

deyfvvtc1#

我现在遇到了完全相同的问题,通过调试androix.compose.ui.focus代码,我可以看到原因。在FocusRequester.kt中存在requestFocus函数。它调用FocusTransactions.kt中的一个内部函数requestFocus。在这里有一个when语句,当我们请求焦点的特定节点是Active、Captured、Deactivated或DeactivedParent时,焦点状态不会发生变化。
问题似乎是,当您请求关注某个节点时,该节点第一次将其初始状态从Inactive变为Active。它仍处于Active状态,因此,如果您请求关注同一个节点,它不会执行任何操作。似乎请求关注另一个节点(如示例代码中所示)会将此状态设置回Inactive。这就是为什么您可以在两个示例节点之间交替焦点,但不能在同一节点上重复焦点请求。
我一直未能找到解决办法(甚至是一个很蹩脚的)。我试着用FocusManager调用clearFocus。也试着用FocusRequester的freeFocus函数,但这只是将捕获状态更改为活动。我认为我们需要在FocusRequester中添加一个新的公共函数,该函数调用FocusTransactions.kt中的clearFocus,因为它将活动状态设置为非活动。这将允许我们在调用requestFocus之前确保状态是正确的。更好的是,我觉得当我们使用talkback遍历时,它应该自动将焦点状态从Active设置为Inactive。
最新的ComposeUI发布说明提到焦点系统是使用新的实验性Modifier.Node API重写的。然而,据我所知,这并没有改变实际的行为。只是焦点系统内部的工作方式。我用最新的alpha版本尝试了你的示例代码,问题仍然存在。

相关问题