I try to add animation to botton navigation appearence slide from the bottom
There is code:
@Composable
private fun BottomNavImpl() {
Scaffold(
bottomBar = {
var isBottomBarVisible: Boolean by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
delay(2000)
isBottomBarVisible = true
}
AnimatedVisibility(
visible = isBottomBarVisible,
enter = slideInVertically(
initialOffsetY = { it },
animationSpec = tween(
durationMillis = 500,
easing = FastOutSlowInEasing
)
),
exit = slideOutVertically(
targetOffsetY = { it },
animationSpec = tween(
durationMillis = 300,
easing = FastOutSlowInEasing
)
)
) {
NavigationBar(
containerColor = Color.Red,
) {
repeat(3) {
NavigationBarItem(
icon = {
Icon(
modifier = Modifier,
painter = painterResource(android.R.drawable.ic_menu_add),
contentDescription = null,
)
},
selected = false,
onClick = { }
)
}
}
}
},
content = { paddingValues ->
Box(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
.background(Color.Green)
) {
}
}
)
}
It provides such a result:
So, the problem is that the white background appears first for the full height and then animation.
What am I missing?
Found out that the issue in the "paddingValues" once "bottomBar" visibility changes, "Scaffold" updates "paddingValues" that cause that "background" appears before animation starts.
Fix is animate "paddingValues" as well:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
Test_delete_itTheme {
var isBottomBarVisible: Boolean by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
while (true) {
delay(2000)
isBottomBarVisible = !isBottomBarVisible
}
}
Scaffold(
modifier = Modifier.fillMaxSize(),
bottomBar = {
AnimatedVisibility(
modifier = Modifier,
visible = isBottomBarVisible,
enter = slideInVertically(
initialOffsetY = { it },
animationSpec = tween(
durationMillis = 500,
easing = FastOutSlowInEasing
)
),
exit = slideOutVertically(
targetOffsetY = { it },
animationSpec = tween(
durationMillis = 300,
easing = FastOutSlowInEasing
)
)
) {
NavigationBar(
containerColor = Color.Red,
) {
repeat(3) {
NavigationBarItem(
modifier = Modifier,
icon = {
Icon(
modifier = Modifier,
painter = painterResource(android.R.drawable.ic_menu_add),
contentDescription = null,
)
},
selected = false,
onClick = { }
)
}
}
}
}
) { innerPadding ->
val targetPadding: PaddingValues = if (isBottomBarVisible) {
innerPadding
} else {
PaddingValues(
top = innerPadding.calculateTopPadding(),
bottom = 0.dp,
start = innerPadding.calculateStartPadding(LayoutDirection.Ltr),
end = innerPadding.calculateEndPadding(LayoutDirection.Ltr)
)
}
val animatedStartPadding by animatePaddingValue(targetPadding.calculateStartPadding(LayoutDirection.Ltr), isBottomBarVisible)
val animatedTopPadding by animatePaddingValue(targetPadding.calculateTopPadding(), isBottomBarVisible)
val animatedEndPadding by animatePaddingValue(targetPadding.calculateEndPadding(LayoutDirection.Ltr), isBottomBarVisible)
val animatedBottomPadding by animatePaddingValue(targetPadding.calculateBottomPadding(), isBottomBarVisible)
Box(
modifier = Modifier
.fillMaxSize()
.padding(
start = animatedStartPadding,
top = animatedTopPadding,
end = animatedEndPadding,
bottom = animatedBottomPadding
)
.background(Color.Green)
) {
}
}
}
}
}
}
@Composable
private fun animatePaddingValue(targetValue: Dp, isBottomBarVisible: Boolean): androidx.compose.runtime.State<Dp> {
val animationSpec = tween<Dp>(
durationMillis = if (isBottomBarVisible) 500 else 300,
easing = FastOutSlowInEasing
)
return animateDpAsState(targetValue = targetValue, animationSpec = animationSpec, label = "")
}