Skip to content

Instantly share code, notes, and snippets.

@SmartToolFactory
Created October 6, 2022 15:58
Show Gist options
  • Save SmartToolFactory/4d1cd8f0f642813ec9af982f130ebc2e to your computer and use it in GitHub Desktop.
Save SmartToolFactory/4d1cd8f0f642813ec9af982f130ebc2e to your computer and use it in GitHub Desktop.
@Composable
private fun AnimatedPieChart() {
val pieData = remember {
mutableStateListOf(
PieData(
startAngle = 0f,
sweepAngle = 180f,
selectedColor = Color(0xffE57373),
unSelectedColor = Color(0xffB71C1C)
),
PieData(
startAngle = 180f,
sweepAngle = 90f,
selectedColor = Color(0xff81C784),
unSelectedColor = Color(0xff1B5E20)
),
PieData(
startAngle = 270f,
sweepAngle = 90f,
selectedColor = Color(0xffFFF176),
unSelectedColor = Color(0xffF57F17)
)
)
}
var selectedIndex by remember {
mutableStateOf(0f)
}
var previousSelectedIndex by remember {
mutableStateOf(0f)
}
var initialRun by remember {
mutableStateOf(true)
}
val selectedItem = pieData[selectedIndex.toInt()]
val angle by remember { mutableStateOf(0f) }
.apply {
value = selectedItem.startAngle + selectedItem.sweepAngle / 2f
}
val updatedAngle by animateFloatAsState(
targetValue = angle,
animationSpec = tween(500, easing = LinearEasing)
)
val animatable = remember {
Animatable(0f)
}
Brush.horizontalGradient()
LaunchedEffect(key1 = selectedIndex) {
if (!initialRun) {
animatable.snapTo(0f)
val result = animatable.animateTo(
targetValue = 1f,
animationSpec = tween(500, easing = LinearEasing)
)
if (!result.endState.isRunning) {
println("ANIMATION END...")
previousSelectedIndex = selectedIndex
}
}
initialRun = false
}
Column {
Slider(
value = selectedIndex, onValueChange = {
selectedIndex = it
},
valueRange = 0f..2f,
steps = 1
)
Canvas(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f)
) {
val canvasWidth = size.width
val canvasHeight = size.height
val arcStrokeWidth = 30.dp.toPx()
val arcHeight = canvasHeight - arcStrokeWidth
pieData.forEachIndexed { index, pieData ->
val colorState = getColorState(
index,
selectedIndex.toInt(),
previousSelectedIndex.toInt()
)
val color = when (colorState) {
ColorState.ActiveColor -> {
pieData.selectedColor
}
ColorState.InActiveColor -> {
pieData.unSelectedColor
}
ColorState.InactiveToActive -> {
getColor(
start = pieData.unSelectedColor,
stop = pieData.selectedColor,
fraction = animatable.value
)
}
else -> {
getColor(
start = pieData.selectedColor,
stop = pieData.unSelectedColor,
fraction = animatable.value
)
}
}
println("🔥 ındex: $index, state: $colorState, color: $color")
drawArc(
color = color,
startAngle = pieData.startAngle,
sweepAngle = pieData.sweepAngle,
topLeft = Offset(
(canvasWidth - arcHeight) / 2,
(canvasHeight - arcHeight) / 2
),
size = Size(arcHeight, arcHeight),
style = Stroke(arcStrokeWidth),
useCenter = false
)
rotate(updatedAngle) {
drawCircle(
Color.Cyan,
center = Offset(arcHeight + arcStrokeWidth / 2, arcHeight / 2),
radius = arcStrokeWidth / 2
)
}
}
}
}
}
fun getColor(
start: Color,
stop: Color,
fraction: Float
): Color {
return lerp(start, stop, fraction)
}
fun getColorState(
index: Int,
selectedIndex: Int,
previousSelectedIndex: Int,
): ColorState {
// changing to unselected
return if (previousSelectedIndex == index && selectedIndex != index) {
ColorState.ActiveToInActive
// changing to unselected
} else if (previousSelectedIndex != index && selectedIndex == index) {
ColorState.InactiveToActive
} else if (previousSelectedIndex != index) {
ColorState.InActiveColor
} else {
ColorState.ActiveColor
}
}
enum class ColorState {
ActiveColor, InActiveColor, ActiveToInActive, InactiveToActive
}
data class PieData(
val startAngle: Float,
val sweepAngle: Float,
val selectedColor: Color,
val unSelectedColor: Color
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment