1
1
/*
2
- * Copyright 2023 The Android Open Source Project
2
+ * Copyright 2025 The Android Open Source Project
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
14
14
* limitations under the License.
15
15
*/
16
16
17
- @file:Suppress(" DEPRECATION_ERROR" )
18
-
19
17
package com.example.compose.snippets.touchinput.focus
20
18
21
- import androidx.compose.foundation.Indication
22
- import androidx.compose.foundation.IndicationInstance
19
+ import androidx.compose.foundation.IndicationNodeFactory
23
20
import androidx.compose.foundation.background
24
21
import androidx.compose.foundation.border
25
22
import androidx.compose.foundation.clickable
26
23
import androidx.compose.foundation.focusGroup
27
24
import androidx.compose.foundation.focusable
25
+ import androidx.compose.foundation.interaction.FocusInteraction
28
26
import androidx.compose.foundation.interaction.InteractionSource
29
27
import androidx.compose.foundation.interaction.MutableInteractionSource
30
- import androidx.compose.foundation.interaction.collectIsFocusedAsState
31
28
import androidx.compose.foundation.layout.Box
32
29
import androidx.compose.foundation.layout.Column
33
30
import androidx.compose.foundation.layout.Row
@@ -42,7 +39,6 @@ import androidx.compose.material3.Text
42
39
import androidx.compose.material3.TextButton
43
40
import androidx.compose.material3.TextField
44
41
import androidx.compose.runtime.Composable
45
- import androidx.compose.runtime.State
46
42
import androidx.compose.runtime.getValue
47
43
import androidx.compose.runtime.mutableStateOf
48
44
import androidx.compose.runtime.remember
@@ -70,9 +66,13 @@ import androidx.compose.ui.input.key.KeyEventType
70
66
import androidx.compose.ui.input.key.key
71
67
import androidx.compose.ui.input.key.onPreviewKeyEvent
72
68
import androidx.compose.ui.input.key.type
69
+ import androidx.compose.ui.node.DelegatableNode
70
+ import androidx.compose.ui.node.DrawModifierNode
71
+ import androidx.compose.ui.node.invalidateDraw
73
72
import androidx.compose.ui.platform.LocalFocusManager
74
73
import androidx.compose.ui.tooling.preview.Preview
75
74
import androidx.compose.ui.unit.dp
75
+ import kotlinx.coroutines.launch
76
76
77
77
@Preview
78
78
@Composable
@@ -436,45 +436,64 @@ private fun ReactToFocus() {
436
436
}
437
437
438
438
// [START android_compose_touchinput_focus_advanced_cues]
439
- private class MyHighlightIndicationInstance (isEnabledState : State <Boolean >) :
440
- IndicationInstance {
441
- private val isEnabled by isEnabledState
442
- override fun ContentDrawScope.drawIndication () {
439
+ private class MyHighlightIndicationNode (private val interactionSource : InteractionSource ) :
440
+ Modifier .Node (), DrawModifierNode {
441
+ private var isFocused = false
442
+
443
+ override fun onAttach () {
444
+ coroutineScope.launch {
445
+ var focusCount = 0
446
+ interactionSource.interactions.collect { interaction ->
447
+ when (interaction) {
448
+ is FocusInteraction .Focus -> focusCount++
449
+ is FocusInteraction .Unfocus -> focusCount--
450
+ }
451
+ val focused = focusCount > 0
452
+ if (isFocused != focused) {
453
+ isFocused = focused
454
+ invalidateDraw()
455
+ }
456
+ }
457
+ }
458
+ }
459
+
460
+ override fun ContentDrawScope.draw () {
443
461
drawContent()
444
- if (isEnabled ) {
462
+ if (isFocused ) {
445
463
drawRect(size = size, color = Color .White , alpha = 0.2f )
446
464
}
447
465
}
448
466
}
467
+
449
468
// [END android_compose_touchinput_focus_advanced_cues]
450
469
451
470
// [START android_compose_touchinput_focus_indication]
452
- class MyHighlightIndication : Indication {
453
- @Composable
454
- override fun rememberUpdatedInstance (interactionSource : InteractionSource ):
455
- IndicationInstance {
456
- val isFocusedState = interactionSource.collectIsFocusedAsState()
457
- return remember(interactionSource) {
458
- MyHighlightIndicationInstance (isEnabledState = isFocusedState)
459
- }
471
+ object MyHighlightIndication : IndicationNodeFactory {
472
+ override fun create (interactionSource : InteractionSource ): DelegatableNode {
473
+ return MyHighlightIndicationNode (interactionSource)
460
474
}
475
+
476
+ override fun hashCode (): Int = - 1
477
+
478
+ override fun equals (other : Any? ) = other == = this
461
479
}
462
480
// [END android_compose_touchinput_focus_indication]
463
481
464
482
@Composable
465
483
private fun ApplyIndication () {
466
484
// [START android_compose_touchinput_focus_apply_indication]
467
- val highlightIndication = remember { MyHighlightIndication () }
468
485
var interactionSource = remember { MutableInteractionSource () }
469
486
470
487
Card (
471
488
modifier = Modifier
472
489
.clickable(
473
490
interactionSource = interactionSource,
474
- indication = highlightIndication ,
491
+ indication = MyHighlightIndication ,
475
492
enabled = true ,
476
493
onClick = { }
477
494
)
478
- ) {}
495
+ ) {
496
+ Text (" hello" )
497
+ }
479
498
// [END android_compose_touchinput_focus_apply_indication]
480
499
}
0 commit comments