What You'll Learn
Material3 Adaptive (ListDetailPaneScaffold, NavigationSuiteScaffold, SupportingPaneScaffold, responsive UI) explained.
Setup
dependencies {
implementation("androidx.compose.material3.adaptive:adaptive:1.1.0")
implementation("androidx.compose.material3.adaptive:adaptive-layout:1.1.0")
implementation("androidx.compose.material3.adaptive:adaptive-navigation:1.1.0")
implementation("androidx.compose.material3:material3-adaptive-navigation-suite:1.3.1")
}
ListDetailPaneScaffold
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun ListDetailScreen(items: List<Item>) {
val navigator = rememberListDetailPaneScaffoldNavigator<Item>()
ListDetailPaneScaffold(
directive = navigator.scaffoldDirective,
value = navigator.scaffoldValue,
listPane = {
AnimatedPane {
LazyColumn {
items(items, key = { it.id }) { item ->
ListItem(
headlineContent = { Text(item.title) },
supportingContent = { Text(item.description) },
modifier = Modifier.clickable {
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
}
)
}
}
}
},
detailPane = {
AnimatedPane {
navigator.currentDestination?.contentKey?.let { item ->
Column(Modifier.fillMaxSize().padding(16.dp)) {
Text(item.title, style = MaterialTheme.typography.headlineMedium)
Spacer(Modifier.height(8.dp))
Text(item.description)
}
} ?: Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text("Select an item")
}
}
}
)
}
NavigationSuiteScaffold
@Composable
fun AdaptiveNavApp() {
var selectedItem by remember { mutableIntStateOf(0) }
val navItems = listOf(
NavItem("Home", Icons.Default.Home),
NavItem("Search", Icons.Default.Search),
NavItem("Settings", Icons.Default.Settings)
)
NavigationSuiteScaffold(
navigationSuiteItems = {
navItems.forEachIndexed { index, item ->
item(
icon = { Icon(item.icon, contentDescription = item.label) },
label = { Text(item.label) },
selected = selectedItem == index,
onClick = { selectedItem = index }
)
}
}
) {
when (selectedItem) {
0 -> HomeContent()
1 -> SearchContent()
2 -> SettingsContent()
}
}
}
// NavigationSuiteScaffold auto-switches based on screen size:
// Compact → NavigationBar (bottom)
// Medium → NavigationRail (side)
// Expanded → NavigationDrawer (permanent)
SupportingPaneScaffold
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun SupportingPaneScreen() {
val navigator = rememberSupportingPaneScaffoldNavigator()
SupportingPaneScaffold(
directive = navigator.scaffoldDirective,
value = navigator.scaffoldValue,
mainPane = {
AnimatedPane {
Column(Modifier.fillMaxSize().padding(16.dp)) {
Text("Main Content", style = MaterialTheme.typography.headlineMedium)
Button(onClick = {
navigator.navigateTo(SupportingPaneScaffoldRole.Supporting)
}) {
Text("Open Support Panel")
}
}
}
},
supportingPane = {
AnimatedPane {
Column(Modifier.fillMaxSize().padding(16.dp)) {
Text("Support Info", style = MaterialTheme.typography.titleMedium)
Text("Additional information displayed here")
}
}
}
)
}
Summary
| Component | Purpose |
|---|---|
ListDetailPaneScaffold |
List-detail layout |
NavigationSuiteScaffold |
Adaptive navigation |
SupportingPaneScaffold |
Main + support panel |
AnimatedPane |
Pane transition animation |
- Material3 Adaptive auto-responds to screen size
-
ListDetailPaneScaffoldauto-builds tablet UI -
NavigationSuiteScaffoldauto-switches Bottom/Rail/Drawer -
AnimatedPanesmooths pane transitions
Ready-Made Android App Templates
8 production-ready Android app templates with Jetpack Compose, MVVM, Hilt, and Material 3.
Browse templates → Gumroad
Top comments (0)