InteractionSource represents a stream of [Interaction]s corresponding to events emitted by a component.
InteractionSourceFlowSample
@Composable
fun InteractionSourceFlowSample() {
// Hoist the MutableInteractionSource that we will provide to interactions
val interactionSource = remember { MutableInteractionSource() }
// Provide the MutableInteractionSource instances to the interactions we want to observe state
// changes for
val draggable =
Modifier.draggable(
interactionSource = interactionSource,
orientation = Orientation.Horizontal,
state = rememberDraggableState { /* update some business state here */ },
)
val clickable =
Modifier.clickable(
interactionSource = interactionSource,
// This component is a compound component where part of it is clickable and part of it
// is
// draggable. As a result we want to show indication for the _whole_ component, and not
// just for clickable area. We set `null` indication here and provide an explicit
// Modifier.indication instance later that will draw indication for the whole component.
indication = null,
) { /* update some business state here */
}
// SnapshotStateList we will use to track incoming Interactions in the order they are emitted
val interactions = remember { mutableStateListOf<Interaction>() }
// Collect Interactions - if they are new, add them to `interactions`. If they represent stop /
// cancel events for existing Interactions, remove them from `interactions` so it will only
// contain currently active `interactions`.
LaunchedEffect(interactionSource) {
interactionSource.interactions.collect { interaction ->
when (interaction) {
is PressInteraction.Press -> interactions.add(interaction)
is PressInteraction.Release -> interactions.remove(interaction.press)
is PressInteraction.Cancel -> interactions.remove(interaction.press)
is DragInteraction.Start -> interactions.add(interaction)
is DragInteraction.Stop -> interactions.remove(interaction.start)
is DragInteraction.Cancel -> interactions.remove(interaction.start)
}
}
}
// Display some text based on the most recent Interaction stored in `interactions`
val text =
when (interactions.lastOrNull()) {
is DragInteraction.Start -> "Dragged"
is PressInteraction.Press -> "Pressed"
else -> "No state"
}
Column(Modifier.fillMaxSize().wrapContentSize()) {
Row(
// Draw indication for the whole component, based on the Interactions dispatched by
// our hoisted MutableInteractionSource
Modifier.indication(
interactionSource = interactionSource,
indication = LocalIndication.current,
)
) {
Box(
Modifier.size(width = 240.dp, height = 80.dp)
.then(clickable)
.border(BorderStroke(3.dp, Color.Blue))
.padding(3.dp)
) {
val pressed = interactions.any { it is PressInteraction.Press }
Text(
text = if (pressed) "Pressed" else "Not pressed",
style = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
modifier = Modifier.fillMaxSize().wrapContentSize(),
)
}
Box(
Modifier.size(width = 240.dp, height = 80.dp)
.then(draggable)
.border(BorderStroke(3.dp, Color.Red))
.padding(3.dp)
) {
val dragged = interactions.any { it is DragInteraction.Start }
Text(
text = if (dragged) "Dragged" else "Not dragged",
style = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
modifier = Modifier.fillMaxSize().wrapContentSize(),
)
}
}
Text(
text = text,
style = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
modifier = Modifier.fillMaxSize().wrapContentSize(),
)
}
}
SimpleInteractionSourceSample
@Composable
fun SimpleInteractionSourceSample() {
// Hoist the MutableInteractionSource that we will provide to interactions
val interactionSource = remember { MutableInteractionSource() }
// Provide the MutableInteractionSource instances to the interactions we want to observe state
// changes for
val draggable =
Modifier.draggable(
interactionSource = interactionSource,
orientation = Orientation.Horizontal,
state = rememberDraggableState { /* update some business state here */ },
)
val clickable =
Modifier.clickable(
interactionSource = interactionSource,
indication = LocalIndication.current,
) { /* update some business state here */
}
// Observe changes to the binary state for these interactions
val isDragged by interactionSource.collectIsDraggedAsState()
val isPressed by interactionSource.collectIsPressedAsState()
// Use the state to change our UI
val (text, color) =
when {
isDragged && isPressed -> "Dragged and pressed" to Color.Red
isDragged -> "Dragged" to Color.Green
isPressed -> "Pressed" to Color.Blue
// Default / baseline state
else -> "Drag me horizontally, or press me!" to Color.Black
}
Box(Modifier.fillMaxSize().wrapContentSize().size(width = 240.dp, height = 80.dp)) {
Box(
Modifier.fillMaxSize()
.then(clickable)
.then(draggable)
.border(BorderStroke(3.dp, color))
.padding(3.dp)
) {
Text(
text,
style = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
modifier = Modifier.fillMaxSize().wrapContentSize(),
)
}
}
}