flutter
/

Flutter Responsive Design – Build Adaptive UIs for Any Screen

Last Sync: Today

On this page

12
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

flutter

Flutter Responsive Design – Build Adaptive UIs for Any Screen

What is Responsive Design?

Responsive design means that your app's layout adapts to the screen size and orientation of the device. It ensures that your app looks good and functions well on everything from small phones to large tablets, foldables, and desktop windows. In Flutter, there are several tools to achieve this: MediaQuery, LayoutBuilder, OrientationBuilder, and flexible widgets like Flexible and Expanded. This guide will teach you how to build truly responsive Flutter apps.

MediaQuery – The Device Screen

MediaQuery provides information about the current device's screen size, orientation, pixel density, and more. You can use it to get the screen dimensions and adjust your UI accordingly.

DARTRead-only
1
final screenSize = MediaQuery.of(context).size;
final width = screenSize.width;
final height = screenSize.height;

// Use width to conditionally layout
if (width > 600) {
  // Tablet or desktop layout
} else {
  // Mobile layout
}

OrientationBuilder – Reacting to Orientation

OrientationBuilder rebuilds its child when the device orientation changes. It gives you the current Orientation (portrait or landscape). This is useful for switching between a vertical list and a grid, for example.

DARTRead-only
1
OrientationBuilder(
  builder: (context, orientation) {
    return GridView.count(
      crossAxisCount: orientation == Orientation.portrait ? 2 : 4,
      children: [...],
    );
  },
)

LayoutBuilder – Knowing Parent Constraints

LayoutBuilder gives you the constraints imposed by the parent widget. This is more powerful than MediaQuery because it reacts to the available space within the layout, not just the screen size. It's ideal for widgets that need to adapt to the space they're given (e.g., inside a drawer or a dialog).

DARTRead-only
1
LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth > 600) {
      return Row(...); // wide layout
    } else {
      return Column(...); // narrow layout
    }
  },
)

FractionallySizedBox – Percentage‑Based Sizing

FractionallySizedBox sizes its child to a fraction of the available space. This is great for creating flexible layouts without hard‑coded pixel values.

DARTRead-only
1
FractionallySizedBox(
  widthFactor: 0.5, // 50% of parent width
  heightFactor: 0.3, // 30% of parent height
  child: Container(color: Colors.blue),
)

Flexible and Expanded – Share Space Dynamically

Flexible and Expanded are used inside Row, Column, and Flex to distribute space among children. Expanded forces the child to fill the remaining space; Flexible allows the child to shrink to its natural size but still be flexible.

DARTRead-only
1
Row(
  children: [
    Flexible(
      flex: 1,
      child: Text('This can wrap'),
    ),
    Expanded(
      flex: 2,
      child: Text('This expands twice as much'),
    ),
  ],
)

Responsive Breakpoints – Classic Approach

Define breakpoints to switch between layouts. Common breakpoints are:

    • Mobile: < 600 dp
    • Tablet: 600 – 1200 dp
    • Desktop: > 1200 dp
DARTRead-only
1
bool isMobile(BuildContext context) => MediaQuery.of(context).size.width < 600;
bool isTablet(BuildContext context) =>
    MediaQuery.of(context).size.width >= 600 &&
    MediaQuery.of(context).size.width < 1200;
bool isDesktop(BuildContext context) =>
    MediaQuery.of(context).size.width >= 1200;

Adaptive vs Responsive

Responsive design usually refers to the layout adapting to screen size (e.g., columns rearrange). Adaptive design goes further: it changes the UI components themselves to suit the platform (e.g., using Cupertino widgets on iOS vs Material on Android). Flutter makes it easy to create both:

DARTRead-only
1
if (Theme.of(context).platform == TargetPlatform.iOS) {
  return CupertinoButton(...);
} else {
  return ElevatedButton(...);
}

Common Responsive Patterns

    • Mobile: Single column, bottom navigation bar.
    • Tablet: Two‑column layout with side navigation or a master‑detail view.
    • Desktop: Multi‑column, side panels, keyboard shortcuts, larger spacing.

Best Practices

    • Avoid hard‑coded pixel values; use percentages, flexible widgets, and layout builders.
    • Test on multiple screen sizes (use device preview in Flutter DevTools).
    • Use MediaQuery.of(context).size sparingly; prefer LayoutBuilder when the size is needed within a subtree.
    • Create reusable responsive widgets that accept width constraints.
    • Use MediaQuery's padding to respect safe areas (notches, status bars).

Common Mistakes

    • Using MediaQuery inside a build method that rebuilds often – can cause performance issues; store values in initState or use LayoutBuilder.
    • Not testing on different screen sizes – assumptions about layout may break.
    • Using Expanded inside a Column without Flexible for wrapping – may cause overflow.
    • Hard‑coding font sizes – use MediaQuery.textScaler or responsive font sizes.

Key Takeaways

    • Responsive design adapts layout to screen size and orientation.
  • -MediaQuery provides screen dimensions and orientation.
    • LayoutBuilder gives you available space constraints from the parent.
    • OrientationBuilder reacts to device orientation changes.
    • Use Flexible, Expanded, and FractionallySizedBox for flexible sizing.
    • Define breakpoints to switch between layouts.
    • Always test on multiple devices and orientations.

Try it yourself

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Responsive Demo',
      home: Scaffold(
        appBar: AppBar(title: const Text('Responsive Layout')),
        body: SafeArea(
          child: Padding(
            padding: const EdgeInsets.all(16),
            child: LayoutBuilder(
              builder: (context, constraints) {
                if (constraints.maxWidth > 600) {
                  // Wide layout
                  return Row(
                    children: [
                      Expanded(
                        child: Container(
                          color: Colors.blue.shade100,
                          padding: const EdgeInsets.all(16),
                          child: const Center(child: Text('Left Panel')),
                        ),
                      ),
                      const SizedBox(width: 16),
                      Expanded(
                        child: Container(
                          color: Colors.green.shade100,
                          padding: const EdgeInsets.all(16),
                          child: const Center(child: Text('Right Panel')),
                        ),
                      ),
                    ],
                  );
                } else {
                  // Narrow layout
                  return Column(
                    children: [
                      Expanded(
                        child: Container(
                          color: Colors.blue.shade100,
                          padding: const EdgeInsets.all(16),
                          child: const Center(child: Text('Top Panel')),
                        ),
                      ),
                      const SizedBox(height: 16),
                      Expanded(
                        child: Container(
                          color: Colors.green.shade100,
                          padding: const EdgeInsets.all(16),
                          child: const Center(child: Text('Bottom Panel')),
                        ),
                      ),
                    ],
                  );
                }
              },
            ),
          ),
        ),
      ),
    );
  }
}

Test Your Knowledge

Q1
of 4

Which widget gives you the screen dimensions?

A
LayoutBuilder
B
MediaQuery
C
OrientationBuilder
D
FractionallySizedBox
Q2
of 4

What does `LayoutBuilder` provide?

A
Screen size and orientation
B
Constraints from the parent widget
C
The device's pixel density
D
The text scaling factor
Q3
of 4

How do you make a widget take 50% of its parent's width?

A
Container(width: MediaQuery.of(context).size.width * 0.5)
B
SizedBox(width: 0.5, child: ...)
C
FractionallySizedBox(widthFactor: 0.5, child: ...)
D
Expanded(child: ...)
Q4
of 4

Which breakpoint is commonly used for tablet layouts?

A
< 600
B
>= 600 and < 1200
C
>= 1200
D
>= 800

Frequently Asked Questions

What is the difference between `MediaQuery` and `LayoutBuilder`?

MediaQuery gives you information about the device screen (size, orientation, etc.). LayoutBuilder gives you the constraints imposed by the parent widget in the tree. LayoutBuilder is more precise for sub‑layouts because it reflects the actual available space, not the whole screen.

How do I make fonts responsive?

You can use MediaQuery.textScaler to get a text scaler, or use MediaQuery.of(context).size.width to calculate font size as a percentage of screen width. However, it's often better to let the user control font size via system settings and use textScaleFactor appropriately.

What is the difference between `Expanded` and `Flexible`?

Expanded forces the child to fill the remaining space (it is a shorthand for Flexible(fit: FlexFit.tight)). Flexible allows the child to take space but also lets it be smaller if its intrinsic size is smaller; it can be used to create flexible layouts where children can shrink.

Should I use `MediaQuery` directly in the `build` method?

It's fine, but be aware that MediaQuery triggers a rebuild when the screen rotates or the size changes. If you only need the value for an initial layout, you can store it in initState and listen to orientation changes with OrientationBuilder if needed.

How do I handle different screen densities (pixel density) for images?

Use AssetImage with flutter's automatic resolution‑aware image handling. Place images in 2.0x, 3.0x folders. For network images, you may need to serve different resolutions based on screen size.

Previous

flutter custom widget

Next

flutter performance

Related Content

Need help?

Explore our comprehensive docs or start a chat with our tech experts.