Skip to content

Instantly share code, notes, and snippets.

@emeowj
Last active October 11, 2024 19:41
Show Gist options
  • Save emeowj/456d5e01d401e807dcbcaa713b6136c8 to your computer and use it in GitHub Desktop.
Save emeowj/456d5e01d401e807dcbcaa713b6136c8 to your computer and use it in GitHub Desktop.
DialControl Refactored
data class DialConfig(
val dialSize: Dp = 240.dp,
val indicatorSize: Dp = 32.dp,
@FloatRange(from = 0.0, to = 1.0) val cutOffFraction: Float = 0.4f,
)
@Composable
private fun <T> DialControl(
options: List<T>,
optionContent: @Composable (T) -> Unit,
config: DialConfig,
modifier: Modifier = Modifier,
dialColor: Color = MaterialTheme.colorScheme.surfaceContainer,
indicator: @Composable () -> Unit,
) {
Box(modifier = modifier.size(config.dialSize), contentAlignment = Alignment.Center) {
DialBackground(
color = dialColor,
cutOffFraction = config.cutOffFraction,
sectionCount = options.size
)
DialContent(
options = options,
optionContent = optionContent,
cutOffFraction = config.cutOffFraction,
dialSize = config.dialSize
)
indicator()
}
}
@Composable
private fun <T> DialContent(
options: List<T>,
optionContent: @Composable (T) -> Unit,
cutOffFraction: Float,
dialSize: Dp
) {
val startDegree = calculateStartAngle(options.size)
val sweep = 360f / options.size
options.forEachIndexed { index, option ->
Box(
modifier = Modifier.graphicsLayer {
val angle = startDegree + sweep * index
val radians = (angle + sweep / 2) * Math.PI / 180
val radius =
(dialSize.toPx() / 2) * (cutOffFraction + (1f - cutOffFraction) / 2)
translationX = (radius * cos(radians)).toFloat()
translationY = (radius * sin(radians)).toFloat()
}
) {
optionContent(option)
}
}
}
@Composable
private fun DialBackground(
color: Color,
cutOffFraction: Float,
sectionCount: Int,
modifier: Modifier = Modifier
) {
Canvas(
modifier = modifier
.fillMaxSize()
.graphicsLayer {
compositingStrategy = CompositingStrategy.Offscreen
}
) {
drawCircle(color = color)
scale(cutOffFraction) {
drawCircle(color = Color.Black, blendMode = BlendMode.Clear)
}
var i = 0
val startDegree = calculateStartAngle(sectionCount)
val sweep = 360f / sectionCount
while (i < sectionCount) {
rotate(startDegree + sweep * i) {
drawLine(
color = Color.Black,
start = center,
end = Offset(x = size.width, y = size.height / 2),
strokeWidth = 6.dp.toPx(),
blendMode = BlendMode.Clear
)
}
i++
}
}
}
private fun calculateStartAngle(sectionCount: Int): Float {
val sweep = 360f / sectionCount
return -90f - sweep / 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment