/* * Copyright 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package androidx.wear.compose.navigation3.samples import androidx.annotation.Sampled import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.navigation3.runtime.NavKey import androidx.navigation3.runtime.entryProvider import androidx.navigation3.runtime.rememberNavBackStack import androidx.navigation3.ui.NavDisplay import androidx.wear.compose.foundation.lazy.TransformingLazyColumn import androidx.wear.compose.foundation.lazy.items import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.Card import androidx.wear.compose.material3.EdgeButton import androidx.wear.compose.material3.ListHeader import androidx.wear.compose.material3.ScreenScaffold import androidx.wear.compose.material3.SurfaceTransformation import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TitleCard import androidx.wear.compose.material3.lazy.rememberTransformationSpec import androidx.wear.compose.material3.lazy.transformedHeight import androidx.wear.compose.navigation3.rememberSwipeDismissableSceneStrategy import kotlinx.serialization.Serializable @Serializable object NotificationList : NavKey @Serializable data class NotificationDetail(val id: Int) : NavKey @Serializable object First : NavKey @Serializable object Second : NavKey data class NotificationItem(val id: Int, val title: String, val body: String) @Sampled @Composable fun ListDetailNavDisplaySample(onExit: () -> Unit = {}) { // Example of using a NavDisplay with SwipeDismissableSceneStrategy for list-detail navigation. // Strongly-typed, serializable navigation destinations are defined at global scope as follows: // @Serializable object NotificationList : NavKey // @Serializable data class NotificationDetail(val id: Int) : NavKey // NotificationItem needs to be defined at top-level or class-level to ensure stability in // Compose: // data class NotificationItem(val id: Int, val title: String, val body: String) val backStack = rememberNavBackStack(NotificationList) val notifications = remember { listOf( NotificationItem( 0, "☕ Coffee Break? Grab a pick-me-up", "Step away from the screen and grab a pick-me-up. Step away from the screen and grab a pick-me-up.", ), NotificationItem( 1, "🌟 You're Awesome!", "Just a little reminder in case you forgot 😊", ), NotificationItem( 2, "👀 Did you know our latest feature?", "Check out [app name]'s latest feature update.", ), NotificationItem( 3, "📅 Appointment Time In 15 Minutes", "Your meeting with [name] is in 15 minutes.", ), ) } NavDisplay( backStack = backStack, sceneStrategies = listOf(rememberSwipeDismissableSceneStrategy()), entryProvider = entryProvider { entry<NotificationList> { val state = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( state, edgeButton = { EdgeButton(onClick = onExit) { Text("Exit") } }, ) { contentPadding -> TransformingLazyColumn(state = state, contentPadding = contentPadding) { item { ListHeader( transformation = SurfaceTransformation(transformationSpec), modifier = Modifier.transformedHeight(this, transformationSpec) .animateItem(), ) { Text("Notifications") } } items(notifications) { notification -> Card( onClick = { backStack.add(NotificationDetail(notification.id)) }, transformation = SurfaceTransformation(transformationSpec), modifier = Modifier.fillMaxWidth() .transformedHeight(this, transformationSpec) .animateItem(), ) { Text(notification.title) } } } } } entry<NotificationDetail> { key -> val item = requireNotNull(notifications.find { item -> item.id == key.id }) ScreenScaffold { contentPadding -> Box( Modifier.fillMaxSize().padding(contentPadding), contentAlignment = Alignment.Center, ) { TitleCard(title = { Text(item.title) }, content = { Text(item.body) }) } } } }, ) } @Sampled @Composable fun NavDisplayWithOnBackBehaviorSample() { // Example of using a NavDisplay with SwipeDismissableSceneStrategy and on back behavior. // Strongly-typed, serializable navigation destinations are defined at global scope as follows: // @Serializable object First: NavKey // @Serializable object Second: NavKey val backStack = rememberNavBackStack(First) var swipedBackCount by remember { mutableIntStateOf(0) } NavDisplay( backStack = backStack, onBack = { swipedBackCount++ backStack.removeLastOrNull() }, sceneStrategies = listOf(rememberSwipeDismissableSceneStrategy()), entryProvider = entryProvider { entry<First> { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Text("First") Spacer(modifier = Modifier.height(16.dp)) Button(onClick = { backStack.add(Second) }) { Text("Second") } Spacer(modifier = Modifier.height(16.dp)) Text("Swiped back $swipedBackCount times") } } entry<Second> { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Text("Second") } } }, ) }
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2026-09-09 UTC.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2026-09-09 UTC."],[],[]]