Created
April 24, 2024 15:49
-
-
Save ardakazanci/5ec373ee38e00af9f04889a2da046d45 to your computer and use it in GitHub Desktop.
Bar with JetpackCompose
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
data class BarDataM(val value: Float, val label: String) | |
@Composable | |
fun BarChartComponent( | |
bars: List<BarDataM>, | |
barWidth: Dp, | |
spaceBetweenBars: Dp, | |
animateChart: Boolean | |
) { | |
var selectedBar by remember { mutableIntStateOf(-1) } | |
var dropRate by remember { mutableFloatStateOf(0f) } | |
val animatedBarHeights = bars.map { bar -> | |
animateFloatAsState( | |
targetValue = if (animateChart) bar.value else 0f, | |
animationSpec = spring( | |
dampingRatio = Spring.DampingRatioMediumBouncy, | |
stiffness = Spring.StiffnessLow | |
) | |
) | |
} | |
Column { | |
Canvas( | |
modifier = Modifier | |
.height(250.dp) | |
.fillMaxWidth() | |
) { | |
val spacingPx = spaceBetweenBars.toPx() | |
val barWidthPx = barWidth.toPx() | |
val path = Path() | |
bars.forEachIndexed { index, bar -> | |
val x = index * (barWidthPx + spacingPx) + spacingPx / 2 | |
val barTopY = size.height - (animatedBarHeights[index].value * size.height) | |
val color = if (index == selectedBar) Color(0xFF51E470) else Color(0XFFE8EAEE) | |
drawRoundRect( | |
color = color, | |
topLeft = Offset(x + 50f, barTopY), | |
size = Size(barWidthPx, animatedBarHeights[index].value * size.height), | |
cornerRadius = CornerRadius(x = 15f, y = 15f) | |
) | |
if (index == 0) { | |
path.moveTo(x + 50f + barWidthPx / 2, barTopY) | |
} else { | |
path.lineTo(x + 50f + barWidthPx / 2, barTopY) | |
} | |
if (index == selectedBar) { | |
val dropText = "$dropRate%" | |
val textPaint = Paint().apply { | |
textSize = 10.sp.toPx() | |
setColor(android.graphics.Color.RED) | |
textAlign = android.graphics.Paint.Align.CENTER | |
} | |
drawContext.canvas.nativeCanvas.drawText( | |
dropText, | |
x + 50f + barWidthPx / 2, | |
barTopY - 10.dp.toPx(), | |
textPaint | |
) | |
} | |
} | |
drawPath( | |
path = path, | |
brush = Brush.linearGradient(listOf(Color.Black, Color.Black.copy(alpha = 0.5f))), | |
style = Stroke(width = 4f) | |
) | |
} | |
Row( | |
modifier = Modifier.fillMaxWidth(), | |
horizontalArrangement = Arrangement.spacedBy( | |
spaceBetweenBars, | |
Alignment.CenterHorizontally | |
) | |
) { | |
bars.forEachIndexed { index, bar -> | |
Box(modifier = Modifier | |
.width(barWidth) | |
.noRippleClickable { | |
selectedBar = index | |
dropRate = Random.nextFloat() * 10 | |
} | |
) { | |
Spacer(modifier = Modifier.height(5.dp)) | |
Text( | |
color = Color.Black.copy(alpha = 0.5f), | |
text = bar.label, | |
fontSize = 12.sp, | |
modifier = Modifier.align(Alignment.Center) | |
) | |
} | |
} | |
} | |
} | |
} | |
@Composable | |
fun Bar() { | |
val bars = listOf( | |
BarDataM(0.7f, "Sun"), | |
BarDataM(0.4f, "Mon"), | |
BarDataM(0.5f, "Tue"), | |
BarDataM(0.6f, "Wed"), | |
BarDataM(0.3f, "Today") | |
) | |
var animateChart by remember { mutableStateOf(false) } | |
Column(horizontalAlignment = Alignment.CenterHorizontally) { | |
Button(onClick = { animateChart = !animateChart }) { | |
Text("Toggle Animation") | |
} | |
BarChartComponent( | |
bars = bars, | |
barWidth = 50.dp, | |
spaceBetweenBars = 20.dp, | |
animateChart = animateChart | |
) | |
} | |
} | |
fun Modifier.noRippleClickable(onClick: () -> Unit): Modifier = composed { | |
this.clickable( | |
indication = null, | |
interactionSource = remember { MutableInteractionSource() }) { | |
onClick() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment