Question #458MediumWidgets & UIImportant

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 DesignDifferent 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

WidgetPurpose
text
LayoutBuilder
Builds based on parent constraints
text
MediaQuery.sizeOf(context)
Gets full window/screen size
text
Flexible
/
text
Expanded
Fills available space proportionally
text
Wrap
Wraps children to next line when no space
text
FractionallySizedBox
Sizes as fraction of parent
text
AspectRatio
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

WidgetPurpose
text
Platform.isIOS
/
text
Platform.isAndroid
Platform detection
text
.adaptive
constructors
Platform-adaptive variants
text
Switch.adaptive()
iOS-style on iOS, Material on Android
text
Slider.adaptive()
Platform-native slider
text
NavigationRail
vs
text
BottomNavigationBar
Desktop vs mobile navigation

Flutter's
text
.adaptive
Constructors

Flutter 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

FeatureResponsiveAdaptive
Layout countOne layout (fluid)Multiple layouts
Adjusts byScreen size continuouslyBreakpoints or platform
ComponentsSame widgets, different sizesDifferent widgets entirely
ExampleGrid changes column countSidebar on desktop, bottom nav on mobile
ComplexitySimplerMore 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:

dart
class 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
    text
    LayoutBuilder
    for local constraints,
    text
    MediaQuery.sizeOf
    for window size
  • Combine both approaches: responsive within each adaptive layout
  • Use Flutter's
    text
    .adaptive
    constructors for platform-native feel
  • 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.