回应焦点

提供视觉提示,更轻松地以可视化方式呈现焦点

虽然 Material 主题中的所有可聚焦元素均已具有与该主题匹配的焦点样式,但您可能需要添加一些视觉元素,以便更容易发现获得焦点的元素。一种很好的解决方案是将元素的边框更改为与背景形成鲜明对比的颜色:

var color by remember { mutableStateOf(Color.White) }
Card(
    modifier = Modifier
        .onFocusChanged {
            color = if (it.isFocused) Red else White
        }
        .border(5.dp, color)
) {}

在此示例中,remember 用于存储重组后的边框颜色,并且每当元素获得或失去焦点时,元素的轮廓都会更新。

实现高级视觉提示

借助 Jetpack Compose,您还可以创建更复杂、更高级的视觉提示,使其更适合您的界面。

  1. 首先,创建一个 IndicationInstance,用于在界面中直观呈现所需的提示:
    private class MyHighlightIndicationInstance(isEnabledState: State<Boolean>) :
        IndicationInstance {
        private val isEnabled by isEnabledState
        override fun ContentDrawScope.drawIndication() {
            drawContent()
            if (isEnabled) {
                drawRect(size = size, color = Color.White, alpha = 0.2f)
            }
        }
    }
  2. 接下来,创建一个 Indication 并记住聚焦状态:
    class MyHighlightIndication : Indication {
        @Composable
        override fun rememberUpdatedInstance(interactionSource: InteractionSource):
            IndicationInstance {
            val isFocusedState = interactionSource.collectIsFocusedAsState()
            return remember(interactionSource) {
                MyHighlightIndicationInstance(isEnabledState = isFocusedState)
            }
        }
    }
  3. 通过 indication() 修饰符将 IndicationInteractionSource 添加到界面:
    val highlightIndication = remember { MyHighlightIndication() }
    var interactionSource = remember { MutableInteractionSource() }
    
    Card(
        modifier = Modifier
            .clickable(
                interactionSource = interactionSource,
                indication = highlightIndication,
                enabled = true,
                onClick = { }
            )
    ) {}

了解焦点的状态

通常,每当焦点的状态发生变化时,FocusEvent 都会触发树,focusable() 修饰符的父级可以使用 onFocusChanged() 修饰符来监听它。

如果您需要了解焦点的状态,可以将以下 API 与 onFocusChanged 修饰符结合使用:

  • 如果附加了修饰符的可组合项已聚焦,则 isFocused 会返回 true
  • hasFocus 的工作方式与 isFocused 类似,但有很大的区别:它会检查相应元素或其某个子元素是否已聚焦,而不是只检查当前元素。
  • 每当按住焦点时,isCaptured 都会返回 true。例如,当 TextField 包含不正确的数据时,就会发生这种情况。因此,尝试聚焦其他元素并不会清除焦点。

这些字段如下所示:

Modifier.onFocusChanged {
    val isFocused = it.isFocused
    val hasFocus = it.hasFocus
    val isCaptured= it.isCaptured
}