main
md 139 lines 6.65 KB
Rendered Raw
1 ---
2 name: flutter-build-responsive-layout
3 description: Use `LayoutBuilder`, `MediaQuery`, or `Expanded/Flexible` to create a layout that adapts to different screen sizes. Use when you need the UI to look good on both mobile and tablet/desktop form factors.
4 metadata:
5 model: models/gemini-3.1-pro-preview
6 last_modified: Tue, 21 Apr 2026 20:17:40 GMT
7 ---
8 # Implementing Adaptive Layouts
9
10 ## Contents
11 - [Space Measurement Guidelines](#space-measurement-guidelines)
12 - [Widget Sizing and Constraints](#widget-sizing-and-constraints)
13 - [Device and Orientation Behaviors](#device-and-orientation-behaviors)
14 - [Workflow: Constructing an Adaptive Layout](#workflow-constructing-an-adaptive-layout)
15 - [Workflow: Optimizing for Large Screens](#workflow-optimizing-for-large-screens)
16 - [Examples](#examples)
17
18 ## Space Measurement Guidelines
19 Determine the available space accurately to ensure layouts adapt to the app window, not just the physical device.
20
21 * **Use `MediaQuery.sizeOf(context)`** to get the size of the entire app window.
22 * **Use `LayoutBuilder`** to make layout decisions based on the parent widget's allocated space. Evaluate `constraints.maxWidth` to determine the appropriate widget tree to return.
23 * **Do not use `MediaQuery.orientationOf` or `OrientationBuilder`** near the top of the widget tree to switch layouts. Device orientation does not accurately reflect the available app window space.
24 * **Do not check for hardware types** (e.g., "phone" vs. "tablet"). Flutter apps run in resizable windows, multi-window modes, and picture-in-picture. Base all layout decisions strictly on available window space.
25
26 ## Widget Sizing and Constraints
27 Understand and apply Flutter's core layout rule: **Constraints go down. Sizes go up. Parent sets position.**
28
29 * **Distribute Space:** Use `Expanded` and `Flexible` within `Row`, `Column`, or `Flex` widgets.
30 * Use `Expanded` to force a child to fill all remaining available space (equivalent to `Flexible` with `fit: FlexFit.tight` and a `flex` factor of 1.0).
31 * Use `Flexible` to allow a child to size itself up to a specific limit while still expanding/contracting. Use the `flex` factor to define the ratio of space consumption among siblings.
32 * **Constrain Width:** Prevent widgets from consuming all horizontal space on large screens. Wrap widgets like `GridView` or `ListView` in a `ConstrainedBox` or `Container` and define a `maxWidth` in the `BoxConstraints`.
33 * **Lazy Rendering:** Always use `ListView.builder` or `GridView.builder` when rendering lists with an unknown or large number of items.
34
35 ## Device and Orientation Behaviors
36 Ensure the app behaves correctly across all device form factors and input methods.
37
38 * **Do not lock screen orientation.** Locking orientation causes severe layout issues on foldable devices, often resulting in letterboxing (the app centered with black borders). Android large format tiers require both portrait and landscape support.
39 * **Fallback for Locked Orientation:** If business requirements strictly mandate a locked orientation, use the `Display API` to retrieve physical screen dimensions instead of `MediaQuery`. `MediaQuery` fails to receive the larger window size in compatibility modes.
40 * **Support Multiple Inputs:** Implement support for basic mice, trackpads, and keyboard shortcuts. Ensure touch targets are appropriately sized and keyboard navigation is accessible.
41
42 ## Workflow: Constructing an Adaptive Layout
43
44 Follow this workflow to implement a layout that adapts to the available `BoxConstraints`.
45
46 **Task Progress:**
47 - [ ] Identify the target widget that requires adaptive behavior.
48 - [ ] Wrap the widget tree in a `LayoutBuilder`.
49 - [ ] Extract the `constraints.maxWidth` from the builder callback.
50 - [ ] Define an adaptive breakpoint (e.g., `largeScreenMinWidth = 600`).
51 - [ ] **If `maxWidth > largeScreenMinWidth`:** Return a large-screen layout (e.g., a `Row` placing a navigation sidebar and content area side-by-side).
52 - [ ] **If `maxWidth <= largeScreenMinWidth`:** Return a small-screen layout (e.g., a `Column` or standard navigation-style approach).
53 - [ ] Run validator -> resize the application window -> review layout transitions -> fix overflow errors.
54
55 ## Workflow: Optimizing for Large Screens
56
57 Follow this workflow to prevent UI elements from stretching unnaturally on large displays.
58
59 **Task Progress:**
60 - [ ] Identify full-width components (e.g., `ListView`, text blocks, forms).
61 - [ ] **If optimizing a list:** Convert `ListView.builder` to `GridView.builder` using `SliverGridDelegateWithMaxCrossAxisExtent` to automatically adjust column counts based on window size.
62 - [ ] **If optimizing a form or text block:** Wrap the component in a `ConstrainedBox`.
63 - [ ] Apply `BoxConstraints(maxWidth: [optimal_width])` to the `ConstrainedBox`.
64 - [ ] Wrap the `ConstrainedBox` in a `Center` widget to keep the constrained content centered on large screens.
65 - [ ] Run validator -> test on desktop/tablet target -> review horizontal stretching -> adjust `maxWidth` or grid extents.
66
67 ## Examples
68
69 ### Adaptive Layout using LayoutBuilder
70 Demonstrates switching between a mobile and desktop layout based on available width.
71
72 ```dart
73 import 'package:flutter/material.dart';
74
75 const double largeScreenMinWidth = 600.0;
76
77 class AdaptiveLayout extends StatelessWidget {
78 const AdaptiveLayout({super.key});
79
80 @override
81 Widget build(BuildContext context) {
82 return LayoutBuilder(
83 builder: (context, constraints) {
84 if (constraints.maxWidth > largeScreenMinWidth) {
85 return _buildLargeScreenLayout();
86 } else {
87 return _buildSmallScreenLayout();
88 }
89 },
90 );
91 }
92
93 Widget _buildLargeScreenLayout() {
94 return Row(
95 children: [
96 const SizedBox(width: 250, child: Placeholder(color: Colors.blue)),
97 const VerticalDivider(width: 1),
98 Expanded(child: const Placeholder(color: Colors.green)),
99 ],
100 );
101 }
102
103 Widget _buildSmallScreenLayout() {
104 return const Placeholder(color: Colors.green);
105 }
106 }
107 ```
108
109 ### Constraining Width on Large Screens
110 Demonstrates preventing a widget from consuming all horizontal space.
111
112 ```dart
113 import 'package:flutter/material.dart';
114
115 class ConstrainedContent extends StatelessWidget {
116 const ConstrainedContent({super.key});
117
118 @override
119 Widget build(BuildContext context) {
120 return Scaffold(
121 body: Center(
122 child: ConstrainedBox(
123 constraints: const BoxConstraints(
124 maxWidth: 800.0, // Maximum width for readability
125 ),
126 child: ListView.builder(
127 itemCount: 50,
128 itemBuilder: (context, index) {
129 return ListTile(
130 title: Text('Item $index'),
131 );
132 },
133 ),
134 ),
135 ),
136 );
137 }
138 }
139 ```