Common Patterns
Full Circle Dial
Section titled “Full Circle Dial”A complete 360° dial starting at 12 o’clock. The thumb can travel all the way around.
var degree by remember { mutableFloatStateOf(0f) }
Dial( degree = degree, onDegreeChange = { degree = it }, modifier = Modifier.size(200.dp), startDegrees = 0f, sweepDegrees = 360f,)Semi-Circle
Section titled “Semi-Circle”A half-arc stretched horizontally across the top. Use DialLayout.height() so the radius is based on the component height rather than width, keeping the arc flush with the edges.
var degree by remember { mutableFloatStateOf(90f) }
Dial( degree = degree, onDegreeChange = { degree = it }, modifier = Modifier.size(200.dp, 100.dp), startDegrees = 270f, sweepDegrees = 180f, layout = DialLayout.height(),)For a true bottom-anchored gauge (the flat edge along the bottom), move the center down and let the radius fill the full height — see DialLayout:
layout = DialLayout( radiusMode = RadiusMode.HEIGHT, radiusFraction = 1f, center = Offset(0.5f, 1f), // center on the bottom edge)Stepped Selector
Section titled “Stepped Selector”Discrete stops like a camera mode dial. Combine interval with animateFloatAsState so the thumb visually snaps to each position.
var degree by remember { mutableFloatStateOf(90f) }val animatedDegree by animateFloatAsState(degree)
Dial( degree = animatedDegree, onDegreeChange = { degree = it }, modifier = Modifier.size(200.dp), startDegrees = -90f, sweepDegrees = 220f, interval = 20f,)Multi-Rotation
Section titled “Multi-Rotation”When sweepDegrees exceeds 360°, the default track stacks completed rotations as fading outer rings. Useful for timers and fine-grained controls.
val sweepDegrees = 360f * 4var degree by remember { mutableFloatStateOf(sweepDegrees) }
Dial( degree = degree, onDegreeChange = { degree = it }, modifier = Modifier.size(300.dp), sweepDegrees = sweepDegrees, interval = 6f,)Programmatic Animation
Section titled “Programmatic Animation”Use State-based API to drive the dial from code with state.animateTo().
val state = rememberDialState()val scope = rememberCoroutineScope()
Dial(state = state, sweepDegrees = 360f)
Button(onClick = { scope.launch { state.animateTo(180f) } }) { Text("Go to halfway")}