adaptive-layout
Adaptive Layout
Adapt to the space you are given, never to the device you think you are on. A phone in a foldable's front display, a resized desktop window, and a tablet in split-screen all defeat Platform.isX checks — but they all report their real constraints. Branch on width, not hardware.
Read the reference for the task at hand:
references/window-size-classes.md— the Material 3 window size-class breakpoints as a shared vocabulary, theWindowSizeClassenum pattern,MediaQuery.sizeOf/paddingOf/viewInsetsOfvs.of, readable max-width, SafeArea and display cutouts, keyboard insets, orientation, foldable hinge awareness.references/list-detail-and-navigation.md— single-pane-navigate vs side-by-side two-pane, choosing the navigation affordance by width and coordinating with the go_router shell, keeping selection state in a Notifier so both panes agree.
Run scripts/check_adaptive.sh before a PR.
Non-negotiable rules
-
Adapt by constraints/size, never by device or platform. No
Platform.isAndroid/Platform.isIOS/kIsWebto pick a layout. UseLayoutBuilder(local box constraints) orMediaQuery.sizeOf(context)(window size). WHY: a resized window, split-screen, and foldable all break device checks; constraints are always true. -
Use the Material 3 window size classes as the breakpoint vocabulary. Compact
<600, medium600–840, expanded840–1200, large1200–1600, extra-large≥1600(logical px width). WHY: these are STANDARD structural breakpoints (not design tokens); one shared enum keeps every screen's breakpoints identical. -
Read the narrowest MediaQuery aspect:
sizeOf/paddingOf/viewInsetsOf/viewPaddingOf, notMediaQuery.of(context). WHY:.ofsubscribes the widget to EVERY MediaQuery change (keyboard, rotation, text scale); the aspect getters rebuild only when that one field changes — seeflutter-performance.