I'm trying to achieve the animation which is shown on the following GIF (mb I should name it differently, instead of "rotate vertically"):
I found the following example https://blog.devgenius.io/animated-bottom-navigation-in-jetpack-compose-af8f590fbeca but it's not actually the same at all, it just bounces the icon, in my case it should just rotate, so in the middle of its animation it looks like this:
You can use AnimatedContent composable to achieve this. Simply it holds more than one state and you can give different layouts to each state.
Here is a sample code.
data class BottomNavItem(
val title: String,
val icon: ImageVector
)
private val navItems = listOf(
BottomNavItem(
"Dashboard",
Icons.Outlined.Info
),
BottomNavItem(
"Browse",
Icons.Outlined.Search
),
BottomNavItem(
"Profile",
Icons.Outlined.Person
)
)
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun AnimatedContentChange() {
var selectedItemIndex by rememberSaveable { mutableStateOf(0) }
NavigationBar(modifier = Modifier.fillMaxWidth()) {
navItems.forEachIndexed { index, item ->
Box(
modifier = Modifier
.weight(1F)
.fillMaxHeight()
.clickable {
selectedItemIndex = index
}, contentAlignment = Alignment.Center
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(4.dp, Alignment.CenterVertically)
) {
val selected = selectedItemIndex == index
AnimatedContent(selected, transitionSpec = {
slideInVertically { if (selected) -it else it } with slideOutVertically { if (selected) it else -it }
}) { isSelected ->
Box(
modifier = Modifier
.padding(vertical = 2.dp)
.size(36.dp)
.clip(RoundedCornerShape(8.dp))
.background(if (isSelected) Color.Blue else Color.LightGray),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = item.icon,
contentDescription = null,
tint = if (isSelected) Color.White else Color.Blue,
modifier = Modifier.fillMaxSize(.5F)
)
}
}
Text(text = item.title)
}
}
}
}
}