3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Jetpack Compose Navigation(BottomNavigation)

Last updated at Posted at 2022-01-20

#目次

  1. Navigationとは
  2. サンプルコード
  3. まとめ

##紹介する実装内容
bottomScreen.gif

##1. Navigationとは

この記事は、Jetpack Compose Scaffold(BottomNavigation UI)で構築したUIをもとに、Navigationを実装するので、UIの説明は省略させていただきます。

NavHostrememberNavControllerを渡し、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に関連する処理だけを説明します。

selectedany{}は、与えられたリストが条件を満たせばBooleanで結果を返してくれるものです。ここで何を確認しているのかというと、BackStack(リスト)から与えられたrouteと、画面を構成してるrouteがマッチしているかを確認しています。

上記のコードを実行すると、

bottomScreen.gif

このように実装することができます。

##3. まとめ

今回は、Scaffoldを用いてBottonNavigationを実装してみました。
画面遷移時の、Argumentsの画面間受け渡し、Nested Navigationを今後改めて説明していきたいと思います。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?