Flutter Responsive Layouts
Phones, tablets, foldables, browsers, and desktop windows all run the same Flutter code. A layout that looks perfect on a small phone may leave huge empty margins on a tablet. Responsive design means the screen adapts to the space available, like water that takes the shape of any glass.
Screen Size Ranges
Developers group screens into ranges called breakpoints. These common values work well as a starting point:
| Range | Width | Typical Device |
|---|---|---|
| Compact | Under 600 | Phone |
| Medium | 600 to 900 | Tablet, foldable |
| Expanded | Over 900 | Laptop, desktop |
0 600 900
├─────────┼─────────────┼──────────────→ width
│ phone │ tablet │ desktop
│ 1 column│ 2 columns │ 3 columns
MediaQuery
MediaQuery reports facts about the whole screen: width, height, orientation, and text scale.
final size = MediaQuery.of(context).size;
final width = size.width;
final isPortrait = MediaQuery.of(context).orientation == Orientation.portrait;
Use it when a decision depends on the full window.
LayoutBuilder
LayoutBuilder reports the space the parent gives to a widget. It suits reusable components, because the widget reacts to its own box and ignores the rest of the screen.
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return WideLayout();
}
return NarrowLayout();
},
)
A Two-Panel Example
A mail app shows a list of messages on a phone and a list beside a reading pane on a tablet.
Phone Tablet
┌───────────┐ ┌────────┬────────────┐
│ Inbox list│ │ Inbox │ Message │
│ │ │ list │ detail │
│ │ │ │ │
└───────────┘ └────────┴────────────┘
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 700) {
return Row(
children: [
Expanded(flex: 1, child: InboxList()),
Expanded(flex: 2, child: MessageDetail()),
],
);
}
return InboxList();
},
);
}
Flexible Building Blocks
Expanded and Flexible
Inside a Row or Column, Expanded fills leftover space. The flex number divides space by ratio: a child with flex: 2 receives twice the room of a child with flex: 1. Flexible lets a child shrink below the available space.
FractionallySizedBox
This widget sizes a child as a fraction of its parent.
FractionallySizedBox(
widthFactor: 0.8,
child: ElevatedButton(onPressed: () {}, child: Text('Continue')),
)
AspectRatio
AspectRatio keeps a fixed shape, such as 16 by 9 for video, at every width.
AspectRatio(
aspectRatio: 16 / 9,
child: Image.asset('assets/banner.png', fit: BoxFit.cover),
)
Wrap
Wrap works like a Row that moves extra items to a new line. Tag chips and filter buttons fit this pattern.
SafeArea
Modern phones have notches, rounded corners, and gesture bars. SafeArea pushes content away from these zones so nothing hides behind them.
Scaffold(
body: SafeArea(
child: Text('Visible content'),
),
)
Text Scaling
Users with low vision raise the system font size. Avoid fixed-height boxes around text, because larger text overflows the box and triggers a yellow-black striped error. Let containers grow with their content.
Orientation Changes
OrientationBuilder rebuilds a layout when the user rotates the device. Switch a two-column grid to four columns in landscape.
OrientationBuilder(
builder: (context, orientation) {
return GridView.count(
crossAxisCount: orientation == Orientation.portrait ? 2 : 4,
children: items,
);
},
)
Testing Your Layout
- Resize the browser window when you run
flutter run -d chrome. - Try a small phone emulator and a tablet emulator.
- Rotate the device in both directions.
- Raise the system font size in device settings.
Choose LayoutBuilder for component-level decisions and MediaQuery for screen-level decisions. Combine both with flexible widgets, and the app looks right everywhere.
Adaptive Versus Responsive
Responsive design stretches and rearranges one layout across sizes. Adaptive design goes further and changes behavior for each platform. A phone app shows a bottom navigation bar, while a desktop app shows a side rail with labels. Flutter supports both styles through NavigationBar and NavigationRail, and a LayoutBuilder decides which one appears.
Input Differences
Phones use fingers, and desktops use a mouse and keyboard. Buttons on touch screens need at least 48 pixels of height for comfortable tapping. Desktop users expect hover effects, scroll bars, and keyboard shortcuts. Test with real input methods when you target several platforms.
