目次
- Navigationとは
- サンプルコード
- まとめ
紹介する実装内容
1. Navigationとは
この記事は、Jetpack Compose Scaffold(BottomNavigation UI)で構築したUIをもとに、Navigationを実装するので、UIの説明は省略させていただきます。
NavHost‥rememberNavControllerを渡し、NavControllerのサブクラスであるNavHostControllerでステートを管理します。
また、NavGraphBuilderを用いて、navgraphに対し画面遷移情報を追加します。
ここで、NavGraphBuilderに、どのようにnavgraphをついかするの??
composableにおいて、routeを渡すことでnavgraphを構成することができます。では、詳細を以下のコードでみてみましょう。
public fun NavGraphBuilder.composable(
route: String,
arguments: List<NamedNavArgument> = emptyList(),
deepLinks: List<NavDeepLink> = emptyList(),
content: @Composable (NavBackStackEntry) -> Unit
) {
addDestination(
ComposeNavigator.Destination(provider[ComposeNavigator::class], content).apply {
this.route = route
arguments.forEach { (argumentName, argument) ->
addArgument(argumentName, argument)
}
deepLinks.forEach { deepLink ->
addDeepLink(deepLink)
}
}
)
}
引数のrouteに注目し、addDestination以下にthis.route = routeとあり、渡したrouteをもとに画面遷移の情報を追加していることがわかります。
また、contentスロットがあるので、コンポーザブルをラムダで呼び出すことができます。その他の引数についての説明は別記事で説明します。
では、どのタイミングでrouteを渡すかというと、以下のようになります。
ここで、sealed class にしている意図として網羅性を担保できることです。
それでは、サンプルコードを用いて実際に画面遷移を行っていきます。
2. サンプルコード
navgraphを作成する。
@Composable
fun ScreenNavigation(
navController: NavHostController
){
NavHost(
navController = navController,
startDestination = Screen.MailScreen.route
){
composable(Screen.MailScreen.route){
MailScreen()
}
composable(Screen.ProfileScreen.route){
ProfileScreen()
}
}
}
NavHostのスロットで、composableは上記のように呼び出します。
次に、ScaffoldのスロットbottomBarで、BottomAppBarを呼び出し、**Scaffoldのcontent(スロット)**で、上記のScreenNavigationを呼び出します。
Scaffoldは、マテリアルコンポーネントを対応する画面上に配置することができます。よって、bottomBarで呼び出しているBottomAppBarのcontent(スロット)で以下のコンポーザブルを呼び出します。
@Composable
fun CustomBottomNav(
navController: NavHostController
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
BottomNavigation(
modifier = Modifier
.padding(0.dp, 0.dp, 0.dp, 5.dp)
.height(100.dp),
elevation = 0.dp
) {
screenItem.forEach { screen ->
BottomItem(
screen = screen,
currentDestination = currentDestination,
navController = navController
)
}
}
}
ここで重要になってくるのは、navgraphで作成した画面遷移がどのように実行されるかを考えることです。
NavHostは、画面遷移を行うためにBackStackを生成します。このBackStackというリストを利用することで、NavHostが再コンポーズされるたびにcomposableで記述したコンポーザブルを呼び出して画面を更新しています。
よって、現状の画面がどのコンポーザブルで構成されているかをBottomNavigationに伝える必要があるので、上記のnavBackStackEntryをステートとして管理し、currentDestinationで、BackStackから更新される画面を受け取ることができます。
最後に、BottonNavigationのスロットで呼び出されている。BottomItemについて確認していきます。
@Composable
fun RowScope.BottomItem(
screen: Screen,
currentDestination: NavDestination?,
navController: NavHostController
){
BottomNavigationItem(
icon = {
Icon(
imageVector = screen.icon,
contentDescription = ""
)
},
selected = currentDestination?.hierarchy?.any {
it.route == screen.route
} == true,
unselectedContentColor = LocalContentColor.current.copy(alpha = ContentAlpha.disabled),
onClick = {
navController.navigate(screen.route)
}
)
}
BottonNavigation内で、コンポーザブルを呼び出すために、上記のコンポーザブルはRowScopeのコンポーザブルとして定義し、スロットで、BottomNavigationItemを呼び出します。
BottomNavigationItemでは、icon, label, selectedなどBottomNavigationを構成する要素を細かく設定することができます。ここでは、BottomNavigationに関連する処理だけを説明します。
selected‥any{}は、与えられたリストが条件を満たせばBooleanで結果を返してくれるものです。ここで何を確認しているのかというと、BackStack(リスト)から与えられたrouteと、画面を構成してるrouteがマッチしているかを確認しています。
上記のコードを実行すると、
このように実装することができます。
3. まとめ
今回は、Scaffoldを用いてBottonNavigationを実装してみました。
画面遷移時の、Argumentsの画面間受け渡し、Nested Navigationを今後改めて説明していきたいと思います。
