これを防ぐ方法を紹介します。
1. NavHost に innerPadding を使わない
Scaffold(
...
) { innerPadding ->
NavHost(
modifier = Modifier.padding(innerPadding), // これはダメ
...
) {
...
NavHost の中の Composable で innerPadding を使うようにします。
Scaffold(
...
) { innerPadding ->
val modifier = Modifier.padding(innerPadding)
NavHost(
...
) {
composable(Destination.Home.route) {
HomeScreen(
onClick = {
navController.navigate("profile")
},
modifier = modifier, // こうする
)
}
...
@Composable
private fun HomeScreen(
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Box(modifier = modifier.fillMaxSize()) {
...
}
}
このとき currentBackStack が null でも BottomNavigation / NavigationBar が表示されるようにしないと bottom padding が 0 になる問題があるので注意してください。
val navBackStackEntry by navController.currentBackStackEntryAsState()
// ここで ?: Destination.Home.route をつけないと HomeScreen() に渡される Modifier で bottom padding が 0 になってしまう
val currentRoute = navBackStackEntry?.destination?.route ?: Destination.Home.route
val routes = remember { Destination.values().map { it.route } }
val showNavigationBar = currentRoute in routes
if (showNavigationBar) {
BottomNavigation {
...
2. BottomNavigation / NavigationBar が表示される画面を nested graph にする
これを
NavHost(
navController = navController,
startDestination = Destination.Home.route
) {
composable(Destination.Home.route) {
HomeScreen(
onClick = {
navController.navigate("profile")
},
modifier = modifier,
)
}
composable(Destination.Settings.route) {
SettingsScreen(
onClick = {
navController.navigate("profile")
},
modifier = modifier,
)
}
composable("profile") {
ProfileScreen(
modifier = modifier,
)
}
}
こうする
NavHost(
navController = navController,
startDestination = "main"
) {
// BottomNavigation / NavigationBar が表示される画面を nested graph にする
navigation(
route = "main",
startDestination = Destination.Home.route
) {
composable(Destination.Home.route) {
HomeScreen(
onClick = {
navController.navigate("profile")
},
modifier = modifier,
)
}
composable(Destination.Settings.route) {
SettingsScreen(
onClick = {
navController.navigate("profile")
},
modifier = modifier,
)
}
}
composable("profile") {
ProfileScreen(
modifier = modifier,
)
}
}
これで、下にずれなくなります。
最後に全体のコードを置いておきます。
enum class Destination(val title: String, val route: String, val imageVector: ImageVector) {
Home("Home", "home", Icons.Filled.Home),
Settings("Settings", "settings", Icons.Filled.Settings)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen() {
val navController = rememberNavController()
Scaffold(
topBar = {
TopAppBar(
title = {
Text("Main")
}
)
},
bottomBar = {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val routes = remember { Destination.values().map { it.route } }
val currentRoute = navBackStackEntry?.destination?.route ?: Destination.Home.route
val showNavigationBar = currentRoute in routes
if (showNavigationBar) {
NavigationBar {
Destination.values().forEach { destination ->
NavigationBarItem(
icon = { Icon(destination.imageVector, contentDescription = null) },
label = { Text(destination.title) },
selected = currentRoute == destination.route,
onClick = {
navController.navigate(destination.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
)
}
}
}
}
) { innerPadding ->
val modifier = Modifier.padding(innerPadding)
NavHost(
navController = navController,
startDestination = "main"
) {
navigation(
route = "main",
startDestination = Destination.Home.route
) {
composable(Destination.Home.route) {
HomeScreen(
onClick = {
navController.navigate("profile")
},
modifier = modifier,
)
}
composable(Destination.Settings.route) {
SettingsScreen(
onClick = {
navController.navigate("profile")
},
modifier = modifier,
)
}
}
composable("profile") {
ProfileScreen(
modifier = modifier,
)
}
}
}
}
@Composable
private fun HomeScreen(
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Box(modifier = modifier.fillMaxSize()) {
Text("home")
Button(onClick = onClick, modifier = Modifier.align(Alignment.BottomCenter)) {
Text("button")
}
}
}
@Composable
private fun SettingsScreen(
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Box(modifier = modifier.fillMaxSize()) {
Text("settings")
Button(onClick = onClick, modifier = Modifier.align(Alignment.BottomCenter)) {
Text("button")
}
}
}
@Composable
private fun ProfileScreen(
modifier: Modifier = Modifier,
) {
Box(modifier = modifier.fillMaxSize()) {
Text("profile")
}
}
0 件のコメント:
コメントを投稿