androidandroid-animationjetpack-compose-animationandroid-jetpack-compose-animation

Rotate icon vertically animation


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


Solution

  • 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)
                    }
                }
            }
        }
    }