1

I'm trying to achieve the animation which is shown on the following GIF (mb I should name it differently, instead of "rotate vertically"):

enter image description here

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:

enter image description here

user924
  • 8,146
  • 7
  • 57
  • 139

1 Answers1

2

You can use AnimatedContent composable to achieve this. Simply it holds more than one state and you can give different layouts to each state.

enter image description here

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)
                }
            }
        }
    }
}
Enes Kayıklık
  • 351
  • 5
  • 12
  • 1
    Awesome. I did something similar but with two `AnimatedVisibility` (enter/exit == slide vertical in/out animations) for selected and unselected icon. But your solution looks nicer., thanks. Only starting with animations on Compose :) – user924 May 08 '23 at 12:38
  • 1
    I optimized some code inside AnimatedVisibility. Also you can check this [article](https://medium.com/androiddevelopers/customizing-animatedcontent-in-jetpack-compose-629c67b45894) to understand transitionSpec etc. – Enes Kayıklık May 08 '23 at 12:41