Created
October 6, 2022 15:58
-
-
Save SmartToolFactory/4d1cd8f0f642813ec9af982f130ebc2e to your computer and use it in GitHub Desktop.
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
@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