响应焦点

提供视觉提示以方便焦点可视化

虽然 Material Theme 的所有可聚焦元素都已具有与主题匹配的焦点样式,但您可能需要添加一些视觉元素,以使聚焦的元素更容易被发现。一个好的解决方案是改变元素的边框,使其颜色与背景形成良好的对比。

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,它在您的 UI 中直观地绘制您想要的提示
    private class MyHighlightIndicationNode(private val interactionSource: InteractionSource) :
        Modifier.Node(), DrawModifierNode {
        private var isFocused = false
    
        override fun onAttach() {
            coroutineScope.launch {
                var focusCount = 0
                interactionSource.interactions.collect { interaction ->
                    when (interaction) {
                        is FocusInteraction.Focus -> focusCount++
                        is FocusInteraction.Unfocus -> focusCount--
                    }
                    val focused = focusCount > 0
                    if (isFocused != focused) {
                        isFocused = focused
                        invalidateDraw()
                    }
                }
            }
        }
    
        override fun ContentDrawScope.draw() {
            drawContent()
            if (isFocused) {
                drawRect(size = size, color = Color.White, alpha = 0.2f)
            }
        }
    }
    
  2. 接下来,创建一个 Indication 并记住聚焦状态
    object MyHighlightIndication : IndicationNodeFactory {
        override fun create(interactionSource: InteractionSource): DelegatableNode {
            return MyHighlightIndicationNode(interactionSource)
        }
    
        override fun hashCode(): Int = -1
    
        override fun equals(other: Any?) = other === this
    }
  3. 通过 indication() 修饰符将 IndicationInteractionSource 都添加到 UI 中
    var interactionSource = remember { MutableInteractionSource() }
    
    Card(
        modifier = Modifier
            .clickable(
                interactionSource = interactionSource,
                indication = MyHighlightIndication,
                enabled = true,
                onClick = { }
            )
    ) {
        Text("hello")
    }

了解焦点状态

通常,每次焦点状态更改时,都会在树中向上触发一个 FocusEvent,并且 focusable() 修饰符的父级可以使用 onFocusChanged() 修饰符监听它。

如果您需要了解焦点状态,可以结合 onFocusChanged 修饰符使用这些 API

  • 如果修饰符所附加的可组合项处于聚焦状态,则 isFocused 返回 true
  • hasFocus 的工作方式与 isFocused 类似,但有一个实质性区别:它不仅检查当前元素,还检查元素或其子元素是否处于聚焦状态
  • 每当焦点被保持时,isCaptured 返回 true。例如,当 TextField 包含不正确的数据时,就会发生这种情况,因此尝试聚焦其他元素将不会清除焦点。

这些字段如下所示

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