Adaptive Design
Design once, run anywhere - phone, tablet, foldable, or desktop. Learn Window Size Classes, BoxWithConstraints, Adaptive Scaffold, and more to scale beautifully across screens.
What you’ll learn
- What is Adaptive Design?
- Window Size Classes (Material 3)
- BoxWithConstraints for responsive swaps
- Navigation Rail vs Bottom Bar
- Lazy Grids & Lists
- TwoPane / SlidingPaneLayout
- Insets & Safe Areas
- Orientation & Posture handling
- Adaptive Scaffold
- Responsive Typography & Spacing
- Multi-device Previews
What is Adaptive Design?
Design once, adapt everywhere - phone, tablet, foldable, desktop.
When to use: Build scalable UIs that adjust layout and navigation by available width.
@Composable
fun AdaptiveApp() {
when (WindowWidthSizeClass.calculate()) {
Compact -> PhoneUI()
Medium -> TabletUI()
Expanded -> DesktopUI()
}
}
Window Size Classes
Material 3’s official breakpoints for adaptive UI.
When to use: Decide single- vs two-pane layouts based on width class.
val window = calculateWindowSizeClass(activity)
if (window.widthSizeClass >= Medium) TwoPaneLayout() else SinglePaneLayout()
BoxWithConstraints
React to available space dynamically.
When to use: Swap content without global window info.
BoxWithConstraints {
if (maxWidth > 600.dp) WideCard() else CompactCard()
}
Navigation Rail vs Bottom Bar
Switch navigation type by width.
When to use: Phones → Bottom Bar, Tablets/Desktop → Navigation Rail.
if (window.widthSizeClass >= Medium) NavigationRail() else NavigationBar()
Lazy Grids & Lists
Fit columns automatically with GridCells.Adaptive.
When to use: Galleries, product grids, dashboards.
LazyVerticalGrid(columns = GridCells.Adaptive(140.dp)) {
items(50) { CardItem(it) }
}
SlidingPaneLayout / TwoPane
Show list and detail side-by-side.
When to use: Master–detail on tablets and foldables.
TwoPane(
first = { ListPane() },
second = { DetailPane() },
strategy = HorizontalTwoPaneStrategy()
)
Insets & Safe Areas
Respect system bars, notches, and gestures.
When to use: Edge-to-edge or immersive layouts.
Column(
Modifier.statusBarsPadding()
.navigationBarsPadding()
) {
Content()
}
Orientation & Posture
Detect fold posture and rotation.
When to use: Optimize dual-screen and landscape UIs.
val posture = windowInfoRepo.windowLayoutInfo.collectAsState()
if (posture.value.displayFeatures.isNotEmpty()) DualPane() else SinglePane()
Adaptive Scaffold
Manage bars, FABs, and inner paddings responsively.
When to use: Base shell for multi-device screens.
Scaffold(
topBar = { TopAppBar(title = { Text("Home") }) },
bottomBar = { if (isCompact) BottomBar() }
) { inner ->
Content(Modifier.padding(inner))
}
Responsive Typography & Spacing
Scale type and padding for readability.
When to use: Larger screens and TV-like distances.
val isLarge = window.widthSizeClass >= Expanded
Text("Hello", fontSize = if (isLarge) 24.sp else 16.sp)
Preview for Devices
Validate layouts on multiple virtual screens.
When to use: Catch adaptive issues before release.
@Preview(device = Devices.TABLET)
@Composable fun PreviewTablet() { AdaptiveApp() }
Final Tips
- Use WindowSizeClass for layout decisions
- Prefer Adaptive Scaffold + Insets
- Test on phones, tablets, foldables
- Avoid hardcoded sizes; keep modifiers flexible
- Preview with multiple configurations
Thank You - Follow Boltuix
Daily Jetpack Compose insights - layouts, adaptive UI, production tips.
#Android #JetpackCompose #MaterialDesign #AdaptiveUI #Kotlin #AndroidDevelopers














