What is the difference between Adaptive and Responsive design in Flutter?
#flutter#responsive#adaptive#layout#mediaquery#layoutbuilder
Answer
Overview
- Responsive Design — The same layout adjusts fluidly to fit different screen sizes (stretching, reflowing, resizing)
- Adaptive Design — Different layouts are chosen based on the platform, device type, or screen size
Responsive Design
Responsive design makes a single layout that adjusts to any screen size. Elements resize, reflow, or reposition based on available space.
dart// Responsive: Same layout adjusts to screen width class ResponsiveHomePage extends StatelessWidget { const ResponsiveHomePage({super.key}); Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { // Same layout — just different column count final crossAxisCount = constraints.maxWidth > 900 ? 4 : constraints.maxWidth > 600 ? 3 : 2; return GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: crossAxisCount, ), itemCount: 20, itemBuilder: (context, index) => ProductCard(index: index), ); }, ); } }
Key Responsive Widgets
| Widget | Purpose |
|---|---|
text | Builds based on parent constraints |
text | Gets full window/screen size |
text text | Fills available space proportionally |
text | Wraps children to next line when no space |
text | Sizes as fraction of parent |
text | Maintains width-to-height ratio |
Adaptive Design
Adaptive design provides completely different layouts or components depending on the platform, device type, or screen size breakpoints.
dart// Adaptive: Different layouts for different platforms/sizes class AdaptiveHomePage extends StatelessWidget { const AdaptiveHomePage({super.key}); Widget build(BuildContext context) { final screenWidth = MediaQuery.sizeOf(context).width; // Completely different layouts if (screenWidth > 1200) { return const DesktopLayout(); // Sidebar + content + details panel } else if (screenWidth > 600) { return const TabletLayout(); // Sidebar + content } else { return const MobileLayout(); // Bottom nav + content } } } // Adaptive: Platform-specific widgets class AdaptiveDialog extends StatelessWidget { Widget build(BuildContext context) { if (Platform.isIOS || Platform.isMacOS) { return CupertinoAlertDialog( title: const Text('Confirm'), actions: [ CupertinoDialogAction(child: const Text('OK')), ], ); } return AlertDialog( title: const Text('Confirm'), actions: [ TextButton(onPressed: () {}, child: const Text('OK')), ], ); } }
Key Adaptive Widgets
| Widget | Purpose |
|---|---|
text text | Platform detection |
text | Platform-adaptive variants |
text | iOS-style on iOS, Material on Android |
text | Platform-native slider |
text text | Desktop vs mobile navigation |
Flutter's text.adaptive
Constructors
text
.adaptiveFlutter provides built-in adaptive widgets:
dart// These automatically adapt to the platform Switch.adaptive( value: _isOn, onChanged: (val) => setState(() => _isOn = val), // Renders CupertinoSwitch on iOS, Material Switch on Android ) Slider.adaptive( value: _volume, onChanged: (val) => setState(() => _volume = val), ) // SliverAppBar can also adapt CircularProgressIndicator.adaptive() // CupertinoActivityIndicator on iOS, CircularProgressIndicator on Android
Key Differences
| Feature | Responsive | Adaptive |
|---|---|---|
| Layout count | One layout (fluid) | Multiple layouts |
| Adjusts by | Screen size continuously | Breakpoints or platform |
| Components | Same widgets, different sizes | Different widgets entirely |
| Example | Grid changes column count | Sidebar on desktop, bottom nav on mobile |
| Complexity | Simpler | More code, better UX |
| Approach | "Fit the space" | "Best for this device" |
Practical Example: Combined Approach
The best Flutter apps use both responsive and adaptive together:
dartclass MasterDetailPage extends StatelessWidget { const MasterDetailPage({super.key}); Widget build(BuildContext context) { final width = MediaQuery.sizeOf(context).width; final isWideScreen = width > 720; // ADAPTIVE: Different layout structure if (isWideScreen) { return Row( children: [ // RESPONSIVE: List takes proportional width SizedBox( width: width * 0.35, // 35% of screen child: const ItemListView(), ), const VerticalDivider(), // RESPONSIVE: Detail fills remaining space const Expanded(child: ItemDetailView()), ], ); } // ADAPTIVE: Completely different UX on mobile return const ItemListView(); // Tap navigates to detail page } }
Best Practices
- Don't check device type (phone vs tablet) — check available space instead
- Use for local constraints,text
LayoutBuilderfor window sizetextMediaQuery.sizeOf - Combine both approaches: responsive within each adaptive layout
- Use Flutter's constructors for platform-native feeltext
.adaptive - Test at multiple widths: 375px (phone), 768px (tablet), 1280px (desktop)
Key Insight: Responsive answers "How does it fit?" — Adaptive answers "What should it be?" The best apps are both: they adapt the layout structure to the device, then make each layout responsive within its space.