@Serializable sealed interface ScreenKey : NavKey { @Serializable object List : ScreenKey @Serializable data class Detail(val itemId: String) : ScreenKey } class DetailViewModel : ViewModel() { var clickCount by mutableStateOf(0) fun onClicked() { clickCount++ } init { Log.e("LOG", "DetailViewModel init") } override fun onCleared() { super.onCleared() Log.e("LOG", "DetailViewModel Cleared") } } class BasicActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { AppNavigator() } } } @Composable fun AppNavigator() { val backStack = rememberNavBackStack(ScreenKey.List) val navTo: (ScreenKey) -> Unit = { backStack.add(it) } val goBack: () -> Unit = { if (backStack.size > 1) backStack.removeLastOrNull() } NavDisplay( backStack = backStack, onBack = { steps -> repeat(steps) { goBack() } }, entryDecorators = listOf( rememberSceneSetupNavEntryDecorator(), rememberSavedStateNavEntryDecorator(), rememberViewModelStoreNavEntryDecorator() ), transitionSpec = { slideInHorizontally(animationSpec = tween(300)) + fadeIn() togetherWith slideOutHorizontally(targetOffsetX = { -it }, animationSpec = tween(300)) + fadeOut() }, popTransitionSpec = { slideInHorizontally(animationSpec = tween(300)) + fadeIn() togetherWith slideOutHorizontally(animationSpec = tween(300)) + fadeOut() }, entryProvider = entryProvider { entry { ListScreen(onItemSelected = navTo) } entry { key -> val vm: DetailViewModel = viewModel() DetailScreen( itemId = key.itemId, vm = vm, onBack = goBack ) } } ) } @Composable fun ListScreen(onItemSelected: (ScreenKey) -> Unit) { Column( Modifier .padding(all = 24.dp) .fillMaxSize() .padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { Text("Item List", style = MaterialTheme.typography.headlineSmall) listOf("A", "B", "C").forEach { id -> Button(onClick = { onItemSelected(ScreenKey.Detail(id)) }) { Text("Go to Detail for $id") } } } } @OptIn(ExperimentalAnimationApi::class) @Composable fun DetailScreen( itemId: String, vm: DetailViewModel, onBack: () -> Unit ) { val animatedCount by animateIntAsState( targetValue = vm.clickCount, animationSpec = tween(durationMillis = 300) ) Column( Modifier .padding(all = 24.dp) .fillMaxSize() .padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Text("Detail: $itemId", style = MaterialTheme.typography.headlineSmall) Text("Clicks: $animatedCount", style = MaterialTheme.typography.bodyLarge) Button(onClick = { vm.onClicked() }) { Text("Increment") } Button(onClick = onBack) { Text("Back") } } }