Skip to content

Instantly share code, notes, and snippets.

@robertlevonyan
Created May 20, 2025 12:56
Show Gist options
  • Save robertlevonyan/651fde33267837e7378f8e199d2c9cb8 to your computer and use it in GitHub Desktop.
Save robertlevonyan/651fde33267837e7378f8e199d2c9cb8 to your computer and use it in GitHub Desktop.
Expressive Button Animation
@Composable
fun ExpressiveButtonAnimation() {
var selectedIndex by remember { mutableIntStateOf(-1) }
val checkedColor = Color(0xFF554F6E)
val uncheckedColor = Color(0xFFEAE5FF)
val icons = listOf(Icons.Outlined.Alarm, Icons.Outlined.LinkOff, Icons.Outlined.Wifi)
var weights = remember { mutableStateListOf(0.85f, 0.65f, 1.5f) }
Box(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFFDAD2FF)),
contentAlignment = Alignment.Center,
) {
Row(
modifier = Modifier
.fillMaxWidth(0.6f)
.padding(horizontal = 8.dp)
) {
icons.forEachIndexed { index, icon ->
ExpressiveFloatingActionButton(
icon = icon,
itemWeight = weights[index],
checked = selectedIndex == index,
checkedColor = checkedColor,
uncheckedColor = uncheckedColor,
onClick = {
selectedIndex = if (index == selectedIndex) {
-1
} else {
index
}
}
)
}
}
}
}
@Composable
fun RowScope.ExpressiveFloatingActionButton(
icon: ImageVector,
itemWeight: Float,
checked: Boolean,
checkedColor: Color,
uncheckedColor: Color,
onClick: () -> Unit,
) {
var shapeSelected by remember { mutableStateOf(false) }
val animatedRadius by animateDpAsState(
targetValue = if (shapeSelected) 6.dp else 16.dp,
label = "animatedRadius"
)
val animatedWeight by animateFloatAsState(
targetValue = if (shapeSelected) 0.25f else 0f
)
val iconSize = 70.dp
IconButton(
modifier = Modifier
.padding(4.dp)
.weight(itemWeight + animatedWeight)
.height(iconSize)
.pointerInput(Unit) {
awaitPointerEventScope {
while (true) {
val event = awaitPointerEvent(PointerEventPass.Main)
event.changes.forEach { pointerInputChange ->
shapeSelected = pointerInputChange.pressed
}
}
}
},
colors = IconButtonDefaults.filledIconButtonColors(
containerColor = if (shapeSelected || checked) checkedColor else uncheckedColor,
contentColor = if (shapeSelected || checked) uncheckedColor else checkedColor,
),
shape = MaterialTheme.shapes.large.copy(CornerSize(animatedRadius)),
onClick = onClick,
) {
Icon(
imageVector = icon,
contentDescription = null,
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment