Popular Searches
Popular Course Categories
Popular Courses

Designing interfaces for multiple screen sizes

Designing interfaces for multiple screen sizes

Flutter Responsive Design


Designing Interfaces for Multiple Screen Sizes in Flutter


Designing interfaces for multiple screen sizes means creating Flutter applications that remain usable, readable, and visually organized across phones, tablets, desktops, web browsers, foldable devices, and resizable application windows. A good multi-screen interface does not simply stretch the same mobile UI onto a larger display. Instead, it responds to the amount of space available and can change layout structure, navigation, spacing, content density, and interaction patterns when necessary.


Flutter describes responsive design as fitting the UI into available space and adaptive design as making the UI usable in that space. In practical applications, both approaches are commonly used together. Flutter Adaptive and Responsive Design Documentation




1. What Does Designing for Multiple Screen Sizes Mean?


Flutter applications can run in environments with very different dimensions. A phone may provide only a few hundred logical pixels of width, while a desktop or browser window may provide considerably more.


The interface should therefore be able to respond to the available space.


Typical Screen Categories



  • Small screens: Phones and narrow application windows.

  • Medium screens: Tablets and medium-sized browser windows.

  • Large screens: Desktop monitors, large tablets, and wide browser windows.

  • Resizable screens: Desktop and web applications whose windows can continuously change size.




2. Why Multiple Screen Sizes Matter


A fixed layout can work correctly on one device and fail on another. For example, a horizontal row containing several buttons may fit on a desktop but overflow on a phone.


Designing for multiple screen sizes helps you:



  • Prevent horizontal overflow.

  • Improve readability.

  • Use available screen space effectively.

  • Support portrait and landscape configurations.

  • Provide appropriate navigation patterns.

  • Improve touch usability.

  • Support mouse and keyboard interaction on larger devices.

  • Handle resizable windows.

  • Support tablets, desktops, web, and foldable devices.

  • Create a consistent experience across platforms.




3. Responsive Design vs Adaptive Design








Responsive DesignAdaptive Design
Fits UI elements into available space.Changes UI structure when necessary.
Adjusts width, spacing, wrapping, and sizing.Can change navigation and overall layout.
Example: cards change from four columns to two columns.Example: bottom navigation changes to a navigation rail.
Focuses on fitting content.Focuses on usability in the available space.

Flutter recommends combining responsive and adaptive techniques rather than treating them as completely separate concepts. Flutter Responsive and Adaptive Design




4. Mobile-First Thinking


Mobile-first design starts with the constraints of a small screen and then progressively enhances the interface for larger screens.


Mobile Layout


+----------------------+
|       App Bar         |
+----------------------+
|                      |
|      Content         |
|                      |
|      Content         |
|                      |
+----------------------+
| Home | Search | User |
+----------------------+

Large Layout


+------------------------------------------------+
| Sidebar |              Main Content             |
|         |                                       |
| Home    |  Cards       Charts       Details    |
| Users   |                                       |
| Orders  |  Table                                |
| Settings|                                       |
+------------------------------------------------+

The goal is not necessarily to make the desktop version look identical to the mobile version. The larger screen can support additional functionality and information simultaneously.




5. Start With Available Space


A common mistake is to determine layout based only on whether a device is called a phone, tablet, or desktop. The actual application window may be smaller or larger than the physical display.


For example:



  • A tablet can run an application in split-screen mode.

  • A desktop application can be resized to a narrow window.

  • A browser can be resized to many different widths.

  • A foldable device can change the available layout area.


Flutter recommends basing layout decisions on available window or widget space rather than hardware categories. Flutter Adaptive Design Best Practices




6. Understanding Logical Pixels


Flutter layouts use logical pixels rather than directly designing against physical pixels. Logical pixels help UI elements maintain a reasonably consistent visual size across displays with different pixel densities.


Container(
  width: 200,
  height: 100,
  child: const Text('Flutter'),
)

The width value represents logical layout space, not a fixed number of physical display pixels.




7. Using MediaQuery


MediaQuery.sizeOf(context) can be used when your decision depends on the size of the application's current window.


final size = MediaQuery.sizeOf(context);

print(size.width);
print(size.height);


Basic Example


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

  @override
  Widget build(BuildContext context) {
    final width = MediaQuery.sizeOf(context).width;

    if (width < 600) {
      return const MobileLayout();
    }

    return const LargeLayout();
  }
}


MediaQuery.sizeOf returns the size of the application's window in logical pixels. Flutter recommends using the more specific sizeOf API when only the size is needed. Flutter MediaQuery and Adaptive Layout Guidance




8. Using LayoutBuilder


LayoutBuilder is useful when a widget should adapt to the amount of space provided by its parent.


LayoutBuilder(
  builder: (context, constraints) {
    return Text(
      'Available width: ${constraints.maxWidth}',
    );
  },
)

The builder receives a BoxConstraints object containing values such as:



  • minWidth

  • maxWidth

  • minHeight

  • maxHeight


Adaptive Example


LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth < 600) {
      return const MobileLayout();
    }

    return const DesktopLayout();
  },
)


Flutter's adaptive tutorial demonstrates using LayoutBuilder and a 600 logical-pixel example breakpoint to switch between small and large layouts. Flutter LayoutBuilder and Adaptive Layout Tutorial




9. MediaQuery vs LayoutBuilder









FeatureMediaQuery.sizeOfLayoutBuilder
MeasuresApplication windowParent-provided constraints
ReturnsSizeBoxConstraints
ScopeWhole application windowSpecific location in widget tree
Useful forGlobal navigation/layout decisionsLocal widget adaptation
ExampleMobile vs desktop navigationCard columns inside a dashboard

Flutter's general adaptive approach recommends choosing between these tools according to whether you need the whole application window size or the constraints available to a particular widget. Flutter General Adaptive Approach




10. Breakpoints


A breakpoint is a point at which the interface changes its layout structure.


Example Breakpoints


const double smallBreakpoint = 600;
const double mediumBreakpoint = 900;

One possible layout strategy is:



  • Below 600: Small/mobile layout.

  • 600 to below 900: Medium/tablet layout.

  • 900 and above: Large/desktop layout.


These values are examples, not universal device definitions. Breakpoints should be chosen based on where your content needs more space or where the structure needs to change.




11. Three-Layout Strategy


LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth < 600) {
      return const MobileLayout();
    }

    if (constraints.maxWidth < 900) {
      return const TabletLayout();
    }

    return const DesktopLayout();
  },
)


This approach is easy to understand and works well when mobile, tablet, and desktop layouts have meaningfully different structures.




12. Designing a Mobile Layout


Mobile screens normally benefit from vertically arranged content.


Scaffold(
  appBar: AppBar(
    title: const Text('Products'),
  ),
  body: ListView(
    padding: const EdgeInsets.all(16),
    children: const [
      ProductCard(),
      ProductCard(),
      ProductCard(),
    ],
  ),
  bottomNavigationBar: NavigationBar(
    selectedIndex: 0,
    destinations: [
      NavigationDestination(
        icon: Icon(Icons.home),
        label: 'Home',
      ),
      NavigationDestination(
        icon: Icon(Icons.shopping_cart),
        label: 'Cart',
      ),
      NavigationDestination(
        icon: Icon(Icons.person),
        label: 'Profile',
      ),
    ],
  ),
)

Mobile Design Principles



  • Use simple navigation.

  • Prefer vertical content flow.

  • Use readable text sizes.

  • Provide comfortable touch targets.

  • Avoid excessive horizontal content.

  • Use scrolling for long content.

  • Keep important actions easy to reach.




13. Designing a Tablet Layout


Tablets can support more content simultaneously.


Row(
  children: [
    SizedBox(
      width: 240,
      child: NavigationPanel(),
    ),
    const VerticalDivider(width: 1),
    Expanded(
      child: MainContent(),
    ),
  ],
)

Other tablet patterns include:



  • Two-column forms.

  • Two-column product grids.

  • Navigation rail.

  • List-detail layouts.

  • Larger cards.

  • Expanded dashboard sections.




14. Designing a Desktop Layout


Desktop applications can use large horizontal space for navigation, content, details, tables, and toolbars.


Row(
  children: [
    SizedBox(
      width: 250,
      child: Sidebar(),
    ),
    const VerticalDivider(width: 1),
    Expanded(
      child: MainContent(),
    ),
  ],
)

Desktop Design Principles



  • Use side navigation where appropriate.

  • Support mouse interaction.

  • Support keyboard interaction.

  • Use hover feedback where useful.

  • Provide keyboard shortcuts for productivity features.

  • Use tables and multi-column layouts when appropriate.

  • Do not stretch every component across the entire screen.




15. Adaptive Navigation


Navigation is one of the most important components to adapt.


Mobile NavigationBar


NavigationBar(
  selectedIndex: 0,
  destinations: const [
    NavigationDestination(
      icon: Icon(Icons.home),
      label: 'Home',
    ),
    NavigationDestination(
      icon: Icon(Icons.search),
      label: 'Search',
    ),
    NavigationDestination(
      icon: Icon(Icons.person),
      label: 'Profile',
    ),
  ],
)

Large Screen NavigationRail


NavigationRail(
  selectedIndex: 0,
  destinations: const [
    NavigationRailDestination(
      icon: Icon(Icons.home),
      label: Text('Home'),
    ),
    NavigationRailDestination(
      icon: Icon(Icons.search),
      label: Text('Search'),
    ),
    NavigationRailDestination(
      icon: Icon(Icons.person),
      label: Text('Profile'),
    ),
  ],
)

Flutter's adaptive guidance gives navigation as an example of a component that may switch between a bottom navigation bar on smaller windows and a navigation rail on larger windows. Flutter Adaptive Navigation Guidance




16. Complete Adaptive Navigation Example


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

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        final isLarge = constraints.maxWidth >= 600;

        if (isLarge) {
          return Scaffold(
            body: Row(
              children: [
                NavigationRail(
                  selectedIndex: 0,
                  destinations: const [
                    NavigationRailDestination(
                      icon: Icon(Icons.home),
                      label: Text('Home'),
                    ),
                    NavigationRailDestination(
                      icon: Icon(Icons.settings),
                      label: Text('Settings'),
                    ),
                  ],
                ),
                const Expanded(
                  child: MainContent(),
                ),
              ],
            ),
          );
        }

        return Scaffold(
          body: const MainContent(),
          bottomNavigationBar: NavigationBar(
            selectedIndex: 0,
            destinations: const [
              NavigationDestination(
                icon: Icon(Icons.home),
                label: 'Home',
              ),
              NavigationDestination(
                icon: Icon(Icons.settings),
                label: 'Settings',
              ),
            ],
          ),
        );
      },
    );
  }
}




17. Designing Flexible Rows


Hard-coded widths can cause problems on small screens. Expanded and Flexible allow widgets to use available space more effectively.


Expanded Example


Row(
  children: [
    Expanded(
      child: Container(
        height: 100,
        child: const Center(
          child: Text('Card 1'),
        ),
      ),
    ),
    const SizedBox(width: 16),
    Expanded(
      child: Container(
        height: 100,
        child: const Center(
          child: Text('Card 2'),
        ),
      ),
    ),
  ],
)



18. Responsive Row to Column


A common pattern is to use a row when enough width is available and a column when width is limited.


LayoutBuilder(
  builder: (context, constraints) {
    final isWide = constraints.maxWidth >= 700;

    if (isWide) {
      return Row(
        children: [
          Expanded(child: ProfileCard()),
          const SizedBox(width: 16),
          Expanded(child: DetailsCard()),
        ],
      );
    }

    return Column(
      children: [
        ProfileCard(),
        const SizedBox(height: 16),
        DetailsCard(),
      ],
    );
  },
)




19. Responsive Grid


Large screens often have enough space to show several cards in one row, while small screens may need one or two cards per row.


LayoutBuilder(
  builder: (context, constraints) {
    int columns;

    if (constraints.maxWidth < 600) {
      columns = 1;
    } else if (constraints.maxWidth < 1000) {
      columns = 2;
    } else {
      columns = 4;
    }

    return GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: columns,
        crossAxisSpacing: 16,
        mainAxisSpacing: 16,
        childAspectRatio: 1.2,
      ),
      itemCount: 12,
      itemBuilder: (context, index) {
        return Card(
          child: Center(
            child: Text('Item ${index + 1}'),
          ),
        );
      },
    );
  },
)




20. Grid Based on Maximum Item Width


For large screens, it is often better to define a maximum desired item width rather than hard-code the number of columns based on device type.


GridView.builder(
  gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
    maxCrossAxisExtent: 280,
    crossAxisSpacing: 16,
    mainAxisSpacing: 16,
    childAspectRatio: 1.2,
  ),
  itemCount: 20,
  itemBuilder: (context, index) {
    return Card(
      child: Center(
        child: Text('Product ${index + 1}'),
      ),
    );
  },
)

Flutter's large-screen guidance specifically recommends using window size and maximum item widths instead of hard-coding a column count based on whether the device is a tablet or another hardware category. Flutter Large Screen Layout Guidance




21. Preventing Excessive Desktop Width


Large displays can create a problem when text fields, articles, forms, or cards become excessively wide.


Center(
  child: ConstrainedBox(
    constraints: const BoxConstraints(
      maxWidth: 900,
    ),
    child: Padding(
      padding: const EdgeInsets.all(24),
      child: MainContent(),
    ),
  ),
)

This technique keeps content within a controlled maximum width while still allowing it to shrink on smaller screens.




22. Responsive Forms


Mobile Form


Column(
  children: [
    TextField(
      decoration: const InputDecoration(
        labelText: 'First Name',
        border: OutlineInputBorder(),
      ),
    ),
    const SizedBox(height: 16),
    TextField(
      decoration: const InputDecoration(
        labelText: 'Last Name',
        border: OutlineInputBorder(),
      ),
    ),
  ],
)

Desktop Form


Row(
  children: [
    Expanded(
      child: TextField(
        decoration: const InputDecoration(
          labelText: 'First Name',
          border: OutlineInputBorder(),
        ),
      ),
    ),
    const SizedBox(width: 16),
    Expanded(
      child: TextField(
        decoration: const InputDecoration(
          labelText: 'Last Name',
          border: OutlineInputBorder(),
        ),
      ),
    ),
  ],
)

Adaptive Form


LayoutBuilder(
  builder: (context, constraints) {
    final isWide = constraints.maxWidth >= 700;

    return isWide
        ? Row(
            children: [
              Expanded(child: FirstNameField()),
              const SizedBox(width: 16),
              Expanded(child: LastNameField()),
            ],
          )
        : Column(
            children: [
              FirstNameField(),
              const SizedBox(height: 16),
              LastNameField(),
            ],
          );
  },
)




23. Responsive Login Interface


Center(
  child: ConstrainedBox(
    constraints: const BoxConstraints(
      maxWidth: 450,
    ),
    child: SingleChildScrollView(
      padding: const EdgeInsets.all(24),
      child: Column(
        children: [
          const FlutterLogo(size: 80),
          const SizedBox(height: 24),
          const Text(
            'Login',
            style: TextStyle(
              fontSize: 28,
              fontWeight: FontWeight.bold,
            ),
          ),
          const SizedBox(height: 24),
          TextField(
            decoration: const InputDecoration(
              labelText: 'Email',
              border: OutlineInputBorder(),
            ),
          ),
          const SizedBox(height: 16),
          TextField(
            obscureText: true,
            decoration: const InputDecoration(
              labelText: 'Password',
              border: OutlineInputBorder(),
            ),
          ),
          const SizedBox(height: 20),
          SizedBox(
            width: double.infinity,
            child: ElevatedButton(
              onPressed: () {},
              child: const Text('Login'),
            ),
          ),
        ],
      ),
    ),
  ),
)



24. Responsive Images


Images should adapt to their available width while maintaining an appropriate aspect ratio.


AspectRatio(
  aspectRatio: 16 / 9,
  child: Image.asset(
    'assets/images/banner.jpg',
    width: double.infinity,
    fit: BoxFit.cover,
  ),
)

Using Flexible Width


ConstrainedBox(
  constraints: const BoxConstraints(
    maxWidth: 700,
  ),
  child: Image.asset(
    'assets/images/product.jpg',
    fit: BoxFit.contain,
  ),
)



25. Responsive Text


Text should remain readable without relying on arbitrary scaling based only on device type.


Text(
  'Flutter Responsive UI',
  style: Theme.of(context).textTheme.headlineMedium,
)

Using theme text styles helps maintain consistency. Also consider user accessibility settings such as text scaling rather than assuming every user has the default text size.


MediaQuery also provides accessibility-related information such as text scaling and high-contrast settings. Flutter SafeArea and MediaQuery




26. Responsive Spacing


LayoutBuilder(
  builder: (context, constraints) {
    final spacing = constraints.maxWidth < 600
        ? 16.0
        : 32.0;

    return Padding(
      padding: EdgeInsets.all(spacing),
      child: const Text('Responsive content'),
    );
  },
)


Spacing should support hierarchy without becoming unnecessarily large on small screens or excessively cramped on large screens.




27. Using Wrap


Wrap is useful when a group of widgets should automatically move to another line when there is not enough horizontal space.


Wrap(
  spacing: 12,
  runSpacing: 12,
  children: [
    Chip(label: Text('Flutter')),
    Chip(label: Text('Dart')),
    Chip(label: Text('Firebase')),
    Chip(label: Text('UI')),
    Chip(label: Text('API')),
  ],
)

Useful Applications



  • Tags.

  • Filters.

  • Category buttons.

  • Action buttons.

  • Search filters.

  • Toolbar actions.




28. Responsive Dashboard


A dashboard can use different layouts depending on available width.


Mobile


Column(
  children: [
    StatsCard(),
    ChartCard(),
    RecentOrders(),
  ],
)

Tablet


Column(
  children: [
    Row(
      children: [
        Expanded(child: StatsCard()),
        Expanded(child: StatsCard()),
      ],
    ),
    ChartCard(),
    RecentOrders(),
  ],
)

Desktop


Column(
  children: [
    Row(
      children: [
        Expanded(child: StatsCard()),
        Expanded(child: StatsCard()),
        Expanded(child: StatsCard()),
        Expanded(child: StatsCard()),
      ],
    ),
    Row(
      children: [
        Expanded(child: ChartCard()),
        Expanded(child: RecentOrders()),
      ],
    ),
  ],
)



29. Responsive List-Detail Interface


A list-detail layout is a common pattern for email applications, contact applications, messaging applications, and administration systems.


LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth >= 700) {
      return Row(
        children: [
          SizedBox(
            width: 300,
            child: ContactList(),
          ),
          const VerticalDivider(width: 1),
          const Expanded(
            child: ContactDetails(),
          ),
        ],
      );
    }

    return ContactList();
  },
)


Flutter's adaptive tutorial uses a similar concept, displaying a sidebar and details together on larger layouts and navigation-based screens on smaller layouts. Flutter Adaptive List-Detail Tutorial




30. Responsive Tables


Large tables can be difficult to display on mobile screens. Instead of forcing a wide table into a narrow viewport, consider changing the representation.


Desktop Table


DataTable(
  columns: const [
    DataColumn(label: Text('Name')),
    DataColumn(label: Text('Email')),
    DataColumn(label: Text('Status')),
    DataColumn(label: Text('Role')),
  ],
  rows: const [
    DataRow(
      cells: [
        DataCell(Text('John')),
        DataCell(Text('[email protected]')),
        DataCell(Text('Active')),
        DataCell(Text('Admin')),
      ],
    ),
  ],
)

Mobile Alternative


ListView(
  children: const [
    Card(
      child: ListTile(
        title: Text('John'),
        subtitle: Text('[email protected]'),
        trailing: Text('Active'),
      ),
    ),
  ],
)

The idea is to preserve the information while changing its presentation when a full table no longer fits comfortably.




31. Responsive Dialogs


Dialog(
  child: ConstrainedBox(
    constraints: const BoxConstraints(
      maxWidth: 500,
    ),
    child: Padding(
      padding: const EdgeInsets.all(24),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          const Text(
            'Confirmation',
            style: TextStyle(fontSize: 22),
          ),
          const SizedBox(height: 16),
          const Text(
            'Are you sure you want to continue?',
          ),
          const SizedBox(height: 20),
          Row(
            mainAxisAlignment: MainAxisAlignment.end,
            children: [
              TextButton(
                onPressed: () {},
                child: const Text('Cancel'),
              ),
              ElevatedButton(
                onPressed: () {},
                child: const Text('Confirm'),
              ),
            ],
          ),
        ],
      ),
    ),
  ),
)



32. SafeArea


SafeArea protects content from system UI such as status bars, display cutouts, and rounded display edges.


Scaffold(
  body: SafeArea(
    child: YourResponsiveContent(),
  ),
)

Flutter recommends using SafeArea where content could otherwise be obscured by physical display features or operating-system UI. Flutter SafeArea Documentation




33. Avoid Orientation-Only Layout Decisions


Orientation alone does not always tell you how much space an application has.


For example:



  • A phone can be in landscape but still have limited width.

  • A tablet can be in portrait and have substantial width.

  • A desktop window can be resized to a narrow shape.


Flutter's adaptive best-practice guidance recommends using available window size through MediaQuery.sizeOf or constraints through LayoutBuilder rather than relying on orientation alone for major layout decisions. Flutter Adaptive Best Practices




34. Avoid Device-Type Checks


Avoid code such as:


if (isPhone) {
  return PhoneLayout();
} else if (isTablet) {
  return TabletLayout();
} else {
  return DesktopLayout();
}

Instead, base the decision on available space:


LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth < 600) {
      return const SmallLayout();
    }

    if (constraints.maxWidth < 900) {
      return const MediumLayout();
    }

    return const LargeLayout();
  },
)


This approach handles resizable windows and multi-window scenarios more reliably because the layout reacts to the actual rendering space. Flutter Device-Type and Window-Size Guidance




35. Designing for Foldable and Multi-Window Devices


Modern applications can run in split-screen or multi-window environments. Foldable devices can also change the available display area when the device changes configuration.


Therefore:



  • Do not assume the application always occupies the entire physical display.

  • Do not assume portrait mode means a narrow application.

  • Do not assume a tablet always has enough width for a desktop-style layout.

  • Use the current application window size when deciding layout.

  • Consider display features such as hinges and folds when they affect the UI.


Flutter's adaptive documentation specifically discusses large screens, foldables, window sizing, and display dimensions. Flutter Large Screens and Foldables




36. Designing for Different Input Devices


Screen size is only one part of multi-device design. The input method also changes.








DeviceCommon InputDesign Considerations
PhoneTouchLarge touch targets and simple gestures.
TabletTouch, keyboardTouch-friendly controls with additional layout space.
DesktopMouse, keyboard, trackpadHover, shortcuts, precise pointer interaction.
WebMouse, keyboard, touchResponsive resizing and multiple input methods.

Flutter's adaptive best practices recommend designing around the strengths of each form factor and supporting different input devices where appropriate. Flutter Input and Form-Factor Guidance




37. Hover Support


Hover feedback can be useful on desktop and web interfaces.


MouseRegion(
  cursor: SystemMouseCursors.click,
  child: GestureDetector(
    onTap: () {},
    child: const Card(
      child: Padding(
        padding: EdgeInsets.all(20),
        child: Text('Hoverable Card'),
      ),
    ),
  ),
)



38. Keyboard Support


Desktop applications can provide keyboard shortcuts for frequently used actions.


Shortcuts(
  shortcuts: const {
    SingleActivator(
      LogicalKeyboardKey.control,
      key: LogicalKeyboardKey.keyS,
    ): SaveIntent(),
  },
  child: Actions(
    actions: {
      SaveIntent: CallbackAction<SaveIntent>(
        onInvoke: (intent) {
          // Save operation.
          return null;
        },
      ),
    },
    child: const Focus(
      autofocus: true,
      child: Text('Press Ctrl+S to save'),
    ),
  ),
)



39. Reusable Responsive Widget


When many screens use the same breakpoints, create a reusable widget.


class ResponsiveLayout extends StatelessWidget {
  final Widget mobile;
  final Widget tablet;
  final Widget desktop;

  const ResponsiveLayout({
    super.key,
    required this.mobile,
    required this.tablet,
    required this.desktop,
  });

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth < 600) {
          return mobile;
        }

        if (constraints.maxWidth < 900) {
          return tablet;
        }

        return desktop;
      },
    );
  }
}


Usage


ResponsiveLayout(
  mobile: const MobileHome(),
  tablet: const TabletHome(),
  desktop: const DesktopHome(),
)



40. Sharing Data Across Layouts


The data and business logic should generally remain independent from the screen-specific presentation.


class Product {
  final String name;
  final double price;

  const Product({
    required this.name,
    required this.price,
  });
}

const products = [
  Product(
    name: 'Laptop',
    price: 75000,
  ),
  Product(
    name: 'Phone',
    price: 45000,
  ),
];


The same data can be displayed differently:


Mobile:
ListView

Tablet:
GridView

Desktop:
GridView + Sidebar + Details




41. Recommended Project Structure


lib/
├── main.dart
├── models/
│   └── product.dart
├── services/
│   └── product_service.dart
├── widgets/
│   ├── product_card.dart
│   ├── responsive_layout.dart
│   └── navigation_panel.dart
├── screens/
│   ├── mobile/
│   │   └── mobile_home.dart
│   ├── tablet/
│   │   └── tablet_home.dart
│   └── desktop/
│       └── desktop_home.dart
└── theme/
    └── app_theme.dart

This is one possible structure. Do not create separate platform-specific files for every widget unless the presentation genuinely needs to differ. Reusable components should remain shared whenever practical.




42. Do Not Duplicate Business Logic


Avoid implementing the same API, validation, database, and business logic separately for every screen size.


                    Shared Data
                        |
                 Business Logic
                        |
          +-------------+-------------+
          |             |             |
       Mobile        Tablet        Desktop
        UI             UI             UI

This architecture makes maintenance easier because the presentation can change while the underlying data and logic remain shared.




43. Complete Multiple-Screen-Size Example


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(
      debugShowCheckedModeBanner: false,
      title: 'Multi Screen UI',
      theme: ThemeData(
        colorSchemeSeed: Colors.blue,
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: LayoutBuilder(
          builder: (context, constraints) {
            if (constraints.maxWidth < 600) {
              return const MobileHome();
            }

            if (constraints.maxWidth < 900) {
              return const TabletHome();
            }

            return const DesktopHome();
          },
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Mobile'),
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: const [
          InfoCard(title: 'Users', value: '1,250'),
          InfoCard(title: 'Orders', value: '850'),
          InfoCard(title: 'Revenue', value: '₹75,000'),
        ],
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Tablet'),
      ),
      body: GridView.count(
        padding: const EdgeInsets.all(24),
        crossAxisCount: 2,
        crossAxisSpacing: 16,
        mainAxisSpacing: 16,
        children: const [
          InfoCard(title: 'Users', value: '1,250'),
          InfoCard(title: 'Orders', value: '850'),
          InfoCard(title: 'Revenue', value: '₹75,000'),
          InfoCard(title: 'Pending', value: '42'),
        ],
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        children: [
          SizedBox(
            width: 240,
            child: Container(
              padding: const EdgeInsets.all(20),
              child: const Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    'My App',
                    style: TextStyle(
                      fontSize: 24,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  SizedBox(height: 30),
                  Text('Dashboard'),
                  SizedBox(height: 20),
                  Text('Users'),
                  SizedBox(height: 20),
                  Text('Orders'),
                  SizedBox(height: 20),
                  Text('Settings'),
                ],
              ),
            ),
          ),
          const VerticalDivider(width: 1),
          Expanded(
            child: GridView.count(
              padding: const EdgeInsets.all(32),
              crossAxisCount: 4,
              crossAxisSpacing: 20,
              mainAxisSpacing: 20,
              children: const [
                InfoCard(title: 'Users', value: '1,250'),
                InfoCard(title: 'Orders', value: '850'),
                InfoCard(title: 'Revenue', value: '₹75,000'),
                InfoCard(title: 'Pending', value: '42'),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class InfoCard extends StatelessWidget {
  final String title;
  final String value;

  const InfoCard({
    super.key,
    required this.title,
    required this.value,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              title,
              style: const TextStyle(fontSize: 18),
            ),
            const SizedBox(height: 8),
            Text(
              value,
              style: const TextStyle(
                fontSize: 26,
                fontWeight: FontWeight.bold,
              ),
            ),
          ],
        ),
      ),
    );
  }
}




44. Common Mistakes


Mistake 1: Fixed Width Everywhere


Container(
  width: 1000,
  child: Content(),
)

This can overflow when the available width is smaller.


Mistake 2: Hard-Coded Device Types


if (isTablet) {
  return TabletUI();
}

Use available window size instead.


Mistake 3: Too Many Breakpoints


Every breakpoint increases layout complexity. Add a breakpoint when the UI structure genuinely needs to change.


Mistake 4: Stretching Everything on Desktop


Large displays require thoughtful maximum widths and content density.


Mistake 5: Ignoring Accessibility


Text scaling, contrast, and input accessibility can affect layout.


Mistake 6: Ignoring Keyboard and Mouse


Desktop and web interfaces should support pointer and keyboard interaction where appropriate.




45. Best Practices for Multiple Screen Sizes



  • Design around available space.

  • Use MediaQuery.sizeOf for whole-window decisions.

  • Use LayoutBuilder for local constraints.

  • Use content-based breakpoints.

  • Keep breakpoints simple.

  • Use flexible widgets instead of unnecessary fixed widths.

  • Use Expanded and Flexible.

  • Use Wrap for automatically flowing content.

  • Use GridView for suitable large-screen content.

  • Use maximum widths for forms and reading content.

  • Use SafeArea where appropriate.

  • Support different input devices.

  • Keep data and business logic shared.

  • Break large widgets into smaller reusable widgets.

  • Test continuously at different window sizes.

  • Avoid unnecessary orientation locks.


Flutter's official adaptive-design best practices emphasize breaking large widgets into smaller components, designing for the strengths of different form factors, avoiding unnecessary orientation locks, avoiding hardware-type checks, and supporting different input devices. Flutter Adaptive Design Best Practices




46. Testing Multiple Screen Sizes


Mobile Testing



  • Small portrait phone.

  • Large portrait phone.

  • Landscape phone.

  • Different text scaling settings.

  • Keyboard-open state.

  • Display cutouts and safe areas.


Tablet Testing



  • Portrait tablet.

  • Landscape tablet.

  • Split-screen configuration.

  • Different tablet widths.

  • Navigation rail.


Desktop Testing



  • Small desktop window.

  • Medium desktop window.

  • Large monitor.

  • Mouse interaction.

  • Keyboard navigation.

  • Hover behavior.


Web Testing


flutter run -d chrome

Resize the browser window continuously and observe whether the layout transitions correctly. Flutter's adaptive tutorial explicitly demonstrates resizing the browser window to test adaptive behavior. Flutter Adaptive Layout Tutorial




47. Practical Project: Multi-Screen E-Commerce UI


Create an e-commerce application with:



  • Product categories.

  • Product cards.

  • Search.

  • Filters.

  • Shopping cart.

  • Product details.

  • Checkout form.

  • User profile.


Mobile


AppBar
   |
Search
   |
Categories
   |
Product List
   |
Bottom Navigation

Tablet


NavigationRail
      |
Categories | Product Grid
           |
           +-- Product Details

Desktop


Sidebar | Header/Search
        |
        +-- Categories
        |
        +-- Product Grid | Filters
        |
        +-- Details Panel
        |
        +-- Cart/Checkout



48. Practical Project: Responsive Admin Panel


A responsive admin panel can adapt as follows:









ComponentMobileTabletDesktop
NavigationNavigationBar/DrawerNavigationRailSidebar
StatsOne columnTwo columnsFour columns
OrdersCardsCondensed tableFull table
FiltersBottom sheetInline/filter panelPersistent filter panel
ChartsStackedTwo-columnMulti-panel



49. Practical Workflow



  1. Identify the content and functionality of the screen.

  2. Design the basic mobile experience.

  3. Identify which components benefit from additional width.

  4. Determine where the layout should change.

  5. Create meaningful breakpoints.

  6. Measure the available space.

  7. Build flexible components.

  8. Change navigation when appropriate.

  9. Limit excessive content width on large screens.

  10. Support relevant input methods.

  11. Test different window sizes.

  12. Fix overflow and accessibility problems.

  13. Refactor repeated layout logic into reusable widgets.




50. Quick Revision


















ConceptPurpose
Responsive UIFits UI elements into available space.
Adaptive UIChanges UI structure when needed.
MediaQuery.sizeOfGets application window size.
LayoutBuilderGets parent-provided constraints.
BreakpointDefines when layout structure changes.
ExpandedUses remaining available space.
FlexibleAllows children to flex within available space.
WrapMoves children onto additional lines.
GridViewCreates two-dimensional layouts.
ConstrainedBoxControls maximum and minimum dimensions.
SafeAreaProtects content from system UI and display cutouts.
NavigationBarUseful for compact navigation layouts.
NavigationRailUseful for wider layouts.
SidebarUseful for large-screen navigation.



51. Practice Exercises



  1. Create a Flutter page that changes from a Column to a Row at a selected breakpoint.

  2. Create a product list that changes into a responsive grid.

  3. Create a mobile NavigationBar and desktop NavigationRail.

  4. Create a list-detail interface for tablet and desktop.

  5. Create a responsive registration form.

  6. Create an adaptive dashboard with statistics cards.

  7. Create a responsive admin table that becomes cards on mobile.

  8. Create a desktop sidebar that disappears on narrow layouts.

  9. Add hover support for desktop users.

  10. Add a keyboard shortcut for an important desktop action.

  11. Test the application by resizing a Chrome window.

  12. Test the same application in portrait and landscape configurations.




52. Key Takeaways



  • Flutter applications can support many different screen sizes from a shared codebase.

  • Do not assume that device type always tells you the available application space.

  • Responsive design helps content fit the available space.

  • Adaptive design can change the structure of the interface.

  • Use MediaQuery.sizeOf for application-window-level decisions.

  • Use LayoutBuilder for local widget constraints.

  • Use content-based breakpoints instead of hardware-specific checks.

  • Mobile layouts often use vertical lists and compact navigation.

  • Tablet layouts can use split views, grids, and navigation rails.

  • Desktop layouts can use sidebars, tables, toolbars, and multiple panels.

  • Use Expanded, Flexible, Wrap, and GridView for flexible layouts.

  • Use ConstrainedBox to avoid excessively wide desktop content.

  • Use SafeArea to protect content from system UI and display cutouts.

  • Support mouse and keyboard interaction where appropriate.

  • Keep data and business logic shared between layouts.

  • Test applications at many window sizes instead of testing only one device.




53. Official Flutter Resources





54. Learn Flutter with JustAcademy


For structured Flutter training and practical application development, visit the JustAcademy Flutter Training Course.


You can also register for a Flutter course demo through the JustAcademy Flutter Course Demo Registration page.




Conclusion


Designing interfaces for multiple screen sizes is an essential Flutter skill for creating applications that work well across phones, tablets, desktops, web browsers, foldables, and resizable windows. The most important principle is to design around the space actually available to the application instead of relying only on device names. Use MediaQuery.sizeOf for application-window decisions and LayoutBuilder for local layout constraints. Combine these tools with flexible widgets such as Expanded, Flexible, Wrap, GridView, ConstrainedBox, and SafeArea. By sharing data and business logic while adapting navigation and presentation where appropriate, you can create maintainable Flutter interfaces that remain usable and organized across many screen sizes.


whatsapp