ConcatenatedBackStackSample
/**
* In this example, changes to a backStack will only affect the states that were passed alongside
* that particular backStack into the [rememberDecoratedNavEntries] call.
*/
@Composable
fun ConcatenatedBackStackSample() {
val tabKeys = listOf(Home, User)
/** set up User entries */
val homeBackStack = rememberNavBackStack(Home)
val homeBackStackNames = homeBackStack.map { (it as SampleKey).name }
val homeTabEntries =
getHomeTabEntries(
backStackString = homeBackStackNames.toString(),
backStack = homeBackStack,
)
/** set up User entries */
val userBackStack = rememberNavBackStack(User)
val userTabEntries =
getUserTabEntries(
backStackString =
(homeBackStackNames + userBackStack.map { (it as SampleKey).name }).toString(),
backStack = userBackStack,
)
/** condition for which tab to switch to */
var currentTab: SampleTabKey by remember { mutableStateOf(Home) }
Scaffold(
bottomBar = {
NavigationBar {
tabKeys.forEach { tab ->
val isSelected = tab == currentTab
NavigationBarItem(
selected = isSelected,
onClick = { currentTab = tab },
icon = { Icon(imageVector = tab.imageVector, contentDescription = null) },
)
}
}
}
) {
/** Swap backStacks based on the current selected tab */
NavDisplay(
entries = if (currentTab == Home) homeTabEntries else homeTabEntries + userTabEntries,
onBack = {
val currBackStack = if (currentTab == Home) homeBackStack else userBackStack
currBackStack.removeLastOrNull()
if (currentTab == User && userBackStack.isEmpty()) {
currentTab = Home
}
},
)
}
}
MultipleBackStackSample
/**
* In this example, a backStack's associated decorator states will swap along with the backStack.
*/
@Composable
fun MultipleBackStackSample() {
val tabKeys = listOf(Home, User)
/** set up User entries */
val homeBackStack = rememberNavBackStack(Home)
val homeTabEntries =
getHomeTabEntries(
backStackString = homeBackStack.map { (it as SampleKey).name }.toString(),
backStack = homeBackStack,
)
/** set up User entries */
val userBackStack = rememberNavBackStack(User)
val userTabEntries =
getUserTabEntries(
backStackString = userBackStack.map { (it as SampleKey).name }.toString(),
backStack = userBackStack,
)
/** condition for which tab to switch to */
var currentTab: SampleTabKey by remember { mutableStateOf(Home) }
Scaffold(
bottomBar = {
NavigationBar {
tabKeys.forEach { tab ->
val isSelected = tab == currentTab
NavigationBarItem(
selected = isSelected,
onClick = { currentTab = tab },
icon = { Icon(imageVector = tab.imageVector, contentDescription = null) },
)
}
}
}
) {
/** Swap backStacks based on the current selected tab */
NavDisplay(
entries = if (currentTab == Home) homeTabEntries else userTabEntries,
onBack = {
val currBackStack = if (currentTab == Home) homeBackStack else userBackStack
currBackStack.removeLastOrNull()
},
)
}
}
SceneNav
@Composable
fun SceneNav() {
val backStack = rememberNavBackStack(Profile)
val showDialog = remember { mutableStateOf(false) }
NavDisplay(
backStack = backStack,
entryDecorators =
listOf(
rememberSaveableStateHolderNavEntryDecorator(),
rememberViewModelStoreNavEntryDecorator(),
),
onBack = { backStack.removeAt(backStack.lastIndex) },
entryProvider =
entryProvider({ NavEntry(it) { Text(text = "Invalid Key") } }) {
entry<Profile> {
val viewModel = viewModel<ProfileViewModel>()
Profile(viewModel, { backStack.add(it) }) {
backStack.removeAt(backStack.lastIndex)
}
}
entry<Scrollable> {
Scrollable({ backStack.add(it) }) { backStack.removeAt(backStack.lastIndex) }
}
entry<DialogBase> {
DialogBase(onClick = { showDialog.value = true }) {
backStack.removeAt(backStack.lastIndex)
}
}
entry<Dashboard>(
metadata =
metadata {
put(NavDisplay.PredictivePopTransitionKey) { swipeEdge: Int ->
if (swipeEdge == NavigationEvent.EDGE_RIGHT) {
slideInHorizontally(tween(700)) { it / 2 } togetherWith
slideOutHorizontally(tween(700)) { -it / 2 }
} else {
slideInHorizontally(tween(700)) { -it / 2 } togetherWith
slideOutHorizontally(tween(700)) { it / 2 }
}
}
}
) { dashboardArgs ->
val userId = dashboardArgs.userId
Dashboard(userId, onBack = { backStack.removeAt(backStack.lastIndex) })
}
},
)
if (showDialog.value) {
DialogContent(onDismissRequest = { showDialog.value = false })
}
}
SceneNavSharedElementSample
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
fun SceneNavSharedElementSample() {
val backStack = rememberNavBackStack(CatList)
SharedTransitionLayout {
NavDisplay(
backStack = backStack,
onBack = { backStack.removeAt(backStack.lastIndex) },
entryProvider =
entryProvider {
entry<CatList> {
CatList(this@SharedTransitionLayout) { cat ->
backStack.add(CatDetail(cat))
}
}
entry<CatDetail> { args ->
CatDetail(args.cat, this@SharedTransitionLayout) {
backStack.removeAt(backStack.lastIndex)
}
}
},
)
}
}
SceneNavSharedEntrySample
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
fun SceneNavSharedEntrySample() {
val backStack = rememberNavBackStack(CatList)
SharedTransitionLayout {
NavDisplay(
backStack = backStack,
onBack = { backStack.removeAt(backStack.lastIndex) },
entryDecorators = listOf(rememberSaveableStateHolderNavEntryDecorator()),
sharedTransitionScope = this,
entryProvider =
entryProvider {
entry<CatList> {
CatList(this@SharedTransitionLayout) { cat ->
backStack.add(CatDetail(cat))
}
}
entry<CatDetail> { args ->
CatDetail(args.cat, this@SharedTransitionLayout) {
backStack.removeAt(backStack.lastIndex)
}
}
},
)
}
}
SceneStateSample
@Suppress("unused")
@Composable
fun SceneStateSample() {
val backStack = rememberSaveable { mutableStateListOf("a", "b") }
val entries =
rememberDecoratedNavEntries(backStack) { key -> NavEntry(key) { Text("Key = $key") } }
val sceneState =
rememberSceneState(
entries,
listOf(SinglePaneSceneStrategy()),
onBack = { backStack.removeLastOrNull() },
)
val currentScene = sceneState.currentScene
val navigationEventState =
rememberNavigationEventState(
currentInfo = SceneInfo(currentScene),
backInfo = sceneState.previousScenes.map { SceneInfo(it) },
)
NavigationBackHandler(
navigationEventState,
isBackEnabled = currentScene.previousEntries.isNotEmpty(),
onBackCompleted = {
// Remove entries from the back stack until we've removed all popped entries
repeat(entries.size - currentScene.previousEntries.size) {
backStack.removeLastOrNull()
}
},
)
NavDisplay(sceneState, navigationEventState)
}