How to attain a UI like this in Compose?
Suppose there is a list of slices:
data class Slice(val value: Float, val color: Color)
Group-1 is 14.6, Red
Group-2 is 61.8, Blue
Group-3 is 23.6, Green
Total 100.0
Canvas is not necessary anyhow.
Updated your Slice data class to contain text to draw Text too. You can remove it if you don't want to draw text
data class Slice(val value: Float, val color: Color, val text: String = "")
And Canvas to draw rectangles and text
@OptIn(ExperimentalTextApi::class)
@Composable
private fun StackedBar(modifier: Modifier, slices: List<Slice>) {
val textMeasurer = rememberTextMeasurer()
val textLayoutResults = remember {
mutableListOf<TextLayoutResult>().apply {
slices.forEach {
val textLayoutResult: TextLayoutResult =
textMeasurer.measure(
text = AnnotatedString(it.text),
style = TextStyle(
color = Color.White,
fontSize = 18.sp
)
)
add(textLayoutResult)
}
}
}
Canvas(modifier = modifier) {
val canvasWidth = size.width
val canvasHeight = size.height
var currentX = 0f
slices.forEachIndexed { index: Int, slice: Slice ->
val width = (slice.value) / 100f * canvasWidth
// Draw Rectangles
drawRect(
color = slice.color, topLeft = Offset(currentX, 0f), size = Size(
width,
canvasHeight
)
)
// Draw Text
val textSize = textLayoutResults[index].size
val style = textLayoutResults[index].layoutInput.style
drawText(
textMeasurer = textMeasurer, text = slice.text, topLeft = Offset(
x = currentX + (width - textSize.height) / 2,
y = (canvasHeight - textSize.height) / 2
),
style = style
)
// Update start position of next rectangle
currentX += width
}
}
}
Usage
Column {
val slices = listOf(
Slice(value = 14.6f, color = Color.Red, text = "55"),
Slice(value = 61.8f, color = Color.Blue, text = "233"),
Slice(value = 23.6f, color = Color.Green, text = "89")
)
StackedBar(
modifier = Modifier
.fillMaxWidth()
.height(100.dp),
slices = slices
)
}
Result
Landscape