Skip to content

Responding to Input

The Dial reports interaction through standard Compose channels: a MutableInteractionSource for drag/hover state, onDegreeChange for live values, and onDegreeChangeFinished for the release.

Pass a MutableInteractionSource to observe the dial’s interaction state:

val interactionSource = remember { MutableInteractionSource() }
val isDragging by interactionSource.collectIsDraggedAsState()
val isHovered by interactionSource.collectIsHoveredAsState()
Dial(
degree = degree,
onDegreeChange = { degree = it },
interactionSource = interactionSource,
)
Text(
text = when {
isDragging -> "Dragging"
isHovered -> "Hovering"
else -> "Idle"
}
)

This is standard Compose InteractionSource — anything that works there works here.

onDegreeChangeFinished fires once when the user lifts their finger or releases the mouse button:

Dial(
degree = degree,
onDegreeChange = { degree = it },
onDegreeChangeFinished = {
println("Settled at $degree°")
},
)

This is useful for triggering side effects — saving preferences, snapping with a custom animation, or logging — without firing on every intermediate drag position.

When using interval or steps, you often want the thumb to visually snap rather than jump. Animate degree with animateFloatAsState and let onDegreeChange update the underlying state:

var degree by remember { mutableFloatStateOf(0f) }
val animatedDegree by animateFloatAsState(
targetValue = degree,
animationSpec = spring(
stiffness = Spring.StiffnessHigh,
dampingRatio = Spring.DampingRatioLowBouncy,
)
)
Dial(
degree = animatedDegree,
onDegreeChange = { degree = it },
interval = 30f,
)

The degree state holds the snapped target; animatedDegree smoothly chases it.

Set enabled = false to make the dial non-interactive. It still renders normally, but ignores drag input and hides the hand cursor on desktop.

Dial(
degree = degree,
onDegreeChange = { degree = it },
enabled = isEditable,
)