RallyDestination でicon、route(destinationを指定するためのString)、表示するComposableをまとめてinterfaceとして定義(本来はComposableは分離するべきとのこと)
Overview, Accounts, Bills で各画面に対する値を指定
/** * Contract for information needed on every Rally navigation destination */ interface RallyDestination { val icon: ImageVector val route: String val screen: @Composable () -> Unit } /** * Rally app navigation destinations */ object Overview : RallyDestination { override val icon = Icons.Filled.PieChart override val route = "overview" override val screen: @Composable () -> Unit = { OverviewScreen() } } object Accounts : RallyDestination { override val icon = Icons.Filled.AttachMoney override val route = "accounts" override val screen: @Composable () -> Unit = { AccountsScreen() } } object Bills : RallyDestination { override val icon = Icons.Filled.MoneyOff override val route = "bills" override val screen: @Composable () -> Unit = { BillsScreen() } }
実際に使う部分は以下
@Composable fun RallyApp() { RallyTheme { var currentScreen: RallyDestination by remember { mutableStateOf(Overview) } Scaffold( topBar = { RallyTabRow( allScreens = rallyTabRowScreens, onTabSelected = { screen -> currentScreen = screen }, currentScreen = currentScreen ) } ) { innerPadding -> Box(Modifier.padding(innerPadding)) { currentScreen.screen() } } } } val rallyTabRowScreens = listOf(Overview, Accounts, Bills)
currentScreenに初期状態としてOverviewを設定
NavController を取得するには、rememberNavController() 関数を呼び出します。これにより、(rememberSaveable を使用して)構成変更後も存続する NavController が作成されて記憶されます。
NavController は常に、コンポーザブル階層の最上位(通常は App コンポーザブル内)に作成して配置します。これにより、NavController を参照する必要があるすべてのコンポーザブルにアクセス権が付与されます。
特定のデスティネーションのコピーがバックスタックの一番上に最大で 1 つだけ配置されるように、Compose Navigation API には launchSingleTop フラグが用意されています。このフラグを次のように navController.navigate() アクションに渡すことができます。
とのことなのでComposableの一番上で
val navController = rememberNavController()
を呼んで使うようにする。
launchSingleTop に関しては全部のnavigate(route)に指定するのは非効率なので拡張関数を定義して使うのが良い
fun NavHostController.navigateSingleTopTo(route: String) = this.navigate(route) { launchSingleTop = true }
これを定義して以下のように使う。
navController.navigateSingleTopTo(newScreen.route)
また、navControllerはナビゲーション階層の最上位に配置し、下位に渡さないようにする。(独立しなくなる)
以下のように実行するメソッドを渡すようにする。
composable(route = Overview.route) { OverviewScreen( onClickSeeAllAccounts = { navController.navigateSingleTopTo(Accounts.route) }, onClickSeeAllBills = { navController.navigateSingleTopTo(Bills.route) } ) }