Popular Searches
Popular Course Categories
Popular Courses

Flutter Mobile, Tablet & Desktop UI

Flutter Mobile, Tablet & Desktop UI

Flutter Responsive Design


Flutter Mobile, Tablet & Desktop UI


Flutter allows developers to build applications from a single codebase that can run across mobile, tablet, desktop, and web environments. However, the same UI should not always be displayed in exactly the same way on every screen. A good Flutter application adapts its layout, navigation, spacing, content density, and interaction patterns according to the space available to it.


Flutter's official adaptive-design guidance explains that responsive design focuses on fitting UI into available space, while adaptive design focuses on making the UI usable in that space. In practice, mobile, tablet, and desktop applications commonly use both approaches together. Flutter Adaptive and Responsive Design Documentation




1. Understanding Mobile, Tablet and Desktop UI


A Flutter application may run in very different environments:



  • Mobile: Small touch-oriented screens with limited horizontal space.

  • Tablet: Larger touch screens that can support multi-column layouts.

  • Desktop: Large windows that usually have mouse, keyboard, trackpad, and larger display space.

  • Web: Browser windows that can be resized to many different widths.


The goal is not simply to create three completely separate applications. Instead, share common data, business logic, and reusable widgets while changing the presentation where necessary.




2. Why Mobile, Tablet and Desktop UI Need Different Layouts


A mobile screen has limited width, so content is generally arranged vertically. A tablet can display more content side-by-side. A desktop window may provide enough space for a sidebar, navigation rail, content area, tables, filters, and additional actions.


Mobile:
+----------------------+
|       App Bar        |
+----------------------+
|                      |
|      Content         |
|                      |
|                      |
+----------------------+
| Home | Search | Me   |
+----------------------+

Tablet:
+--------------------------------+
|            App Bar             |
+--------------------------------+
| Navigation |    Main Content   |
|            |                   |
|            |                   |
+--------------------------------+

Desktop:
+------------------------------------------------+
| Sidebar |        Main Content      | Details   |
|         |                           |           |
|         |                           |           |
|         |                           |           |
+------------------------------------------------+




3. Mobile UI Design


Mobile interfaces generally have limited horizontal space and are primarily touch-driven. Therefore, mobile UI should prioritize simple navigation, readable content, large touch targets, and vertical scrolling.


Common Mobile UI Components



  • AppBar

  • NavigationBar

  • Drawer

  • ListView

  • GridView

  • BottomSheet

  • FloatingActionButton

  • SafeArea

  • SingleChildScrollView


Example Mobile Scaffold


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

NavigationBar is a Material 3 component designed for persistent navigation between primary destinations. Flutter NavigationBar API




4. Tablet UI Design


Tablets provide significantly more horizontal space than phones. Instead of simply enlarging the mobile layout, developers can use the additional space to show more information simultaneously.


Common Tablet Patterns



  • Two-column layouts.

  • Navigation rail.

  • List and detail views side-by-side.

  • Two or three-column grids.

  • Wider forms.

  • More visible actions.

  • Expanded dashboards.


Example Tablet Layout


Row(
  children: [
    SizedBox(
      width: 250,
      child: ListView(
        children: const [
          ListTile(title: Text('Dashboard')),
          ListTile(title: Text('Products')),
          ListTile(title: Text('Orders')),
        ],
      ),
    ),
    const VerticalDivider(width: 1),
    const Expanded(
      child: Center(
        child: Text('Main Content'),
      ),
    ),
  ],
)



5. Desktop UI Design


Desktop applications have large horizontal and vertical space and commonly support mouse, keyboard, trackpad, hover interactions, keyboard shortcuts, context menus, and resizable windows.


Common Desktop UI Components



  • Sidebar navigation.

  • Navigation rail.

  • Navigation drawer.

  • Data tables.

  • Multi-column dashboards.

  • Toolbars.

  • Search fields.

  • Context menus.

  • Hover interactions.

  • Keyboard shortcuts.

  • Resizable content areas.


Example Desktop Layout


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

Flutter's adaptive guidance recommends designing for the strengths of each form factor rather than simply making every platform look identical. Flutter Adaptive Design Best Practices




6. Mobile vs Tablet vs Desktop












FeatureMobileTabletDesktop
Screen SpaceLimitedMedium/LargeLarge
Primary InputTouchTouch + KeyboardMouse + Keyboard + Trackpad
NavigationNavigationBar/DrawerNavigationRail/NavigationBarSidebar/Rail
ContentMostly single-columnMulti-columnMulti-column
FormsStackedPartially horizontalMulti-column where appropriate
TablesOften replaced by cards/listsCondensed tablesFull tables
DialogsCompactMediumConstrained desktop dialog
InteractionTouch-firstTouch + pointerPointer + keyboard



7. Responsive and Adaptive Design


Responsive design changes the placement and sizing of UI elements so they fit the available space. Adaptive design can change the actual structure of the interface.


Responsive Example


Row(
  children: [
    Expanded(child: Card()),
    Expanded(child: Card()),
  ],
)

Adaptive Example


if (isSmallScreen) {
  return const MobileLayout();
}

return const DesktopLayout();


Flutter recommends measuring the current available window or widget constraints instead of assuming that a physical device type always corresponds to a particular amount of application space. Flutter General Approach to Adaptive Apps




8. Choosing Breakpoints


Breakpoints determine when your UI changes its structure. A commonly used example is:


const mobileBreakpoint = 600.0;
const tabletBreakpoint = 900.0;

Example:



  • Below 600: Mobile-style layout.

  • 600 to below 900: Tablet-style layout.

  • 900 and above: Desktop-style layout.


These numbers are examples rather than universal device classifications. Flutter's adaptive documentation uses 600 logical pixels as a common example for switching between small and larger layouts, but breakpoints should ultimately be chosen according to the needs of the UI. Flutter Adaptive Layout Tutorial




9. Using MediaQuery


MediaQuery.sizeOf(context) is useful when you need to know the size of the application's current window.


final size = MediaQuery.sizeOf(context);

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

return const LargeLayout();


Complete 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();
    }

    if (width < 900) {
      return const TabletLayout();
    }

    return const DesktopLayout();
  }
}




10. Using LayoutBuilder


LayoutBuilder is useful when the decision should be based on the space available to a particular widget rather than the entire application window.


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

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

    return const DesktopLayout();
  },
)


The builder receives a BoxConstraints object containing the minimum and maximum width and height available from the parent. MediaQuery and LayoutBuilder Guidance




11. MediaQuery vs LayoutBuilder








MediaQueryLayoutBuilder
Measures the application window.Measures the constraints provided by the parent.
Useful for full-screen adaptive decisions.Useful for local widget adaptation.
Returns window size information.Provides BoxConstraints.
Good for application navigation.Good for adaptive cards/components.



12. Adaptive Navigation


Navigation is one of the most visible differences between mobile, tablet, and desktop UI.


Mobile


NavigationBar(
  selectedIndex: 0,
  destinations: const [
    NavigationDestination(
      icon: Icon(Icons.home),
      label: 'Home',
    ),
    NavigationDestination(
      icon: Icon(Icons.settings),
      label: 'Settings',
    ),
  ],
)

Tablet/Desktop


NavigationRail(
  selectedIndex: 0,
  destinations: const [
    NavigationRailDestination(
      icon: Icon(Icons.home),
      label: Text('Home'),
    ),
    NavigationRailDestination(
      icon: Icon(Icons.settings),
      label: Text('Settings'),
    ),
  ],
)

NavigationRail is intended for wider layouts such as desktop or tablet landscape layouts, while a bottom navigation pattern is generally better suited to smaller layouts. Flutter NavigationRail API




13. Adaptive Navigation Example


class AdaptiveNavigation extends StatelessWidget {
  const AdaptiveNavigation({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.person),
                      label: Text('Profile'),
                    ),
                  ],
                ),
                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.person),
                label: 'Profile',
              ),
            ],
          ),
        );
      },
    );
  }
}




14. Mobile List UI


Mobile applications commonly display information as vertically scrolling lists.


ListView.builder(
  padding: const EdgeInsets.all(16),
  itemCount: products.length,
  itemBuilder: (context, index) {
    final product = products[index];

    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      child: ListTile(
        leading: const Icon(Icons.shopping_bag),
        title: Text(product.name),
        subtitle: Text(product.price),
        trailing: const Icon(Icons.chevron_right),
      ),
    );
  },
)




15. Tablet Product Grid


On larger screens, a list can often become a grid so that the additional horizontal space is used effectively.


GridView.builder(
  padding: const EdgeInsets.all(24),
  gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
    maxCrossAxisExtent: 280,
    crossAxisSpacing: 16,
    mainAxisSpacing: 16,
    childAspectRatio: 0.8,
  ),
  itemCount: products.length,
  itemBuilder: (context, index) {
    return ProductCard(
      product: products[index],
    );
  },
)

Flutter's large-screen guidance recommends grid-based approaches for avoiding overly wide content and suggests basing grid sizing on available window space rather than hard-coding a device-specific number of columns. Flutter Large Screen Guidance




16. Adaptive Product Grid


LayoutBuilder(
  builder: (context, constraints) {
    return GridView.builder(
      padding: const EdgeInsets.all(20),
      gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
        maxCrossAxisExtent: constraints.maxWidth < 600
            ? 500
            : 280,
        crossAxisSpacing: 16,
        mainAxisSpacing: 16,
        childAspectRatio: 0.8,
      ),
      itemCount: products.length,
      itemBuilder: (context, index) {
        return ProductCard(
          product: products[index],
        );
      },
    );
  },
)



17. Mobile Form UI


Forms on mobile are generally arranged vertically because horizontal space is limited.


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



18. Tablet/Desktop Form UI


On wider screens, related fields can be placed side-by-side.


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;

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

    return Column(
      children: [
        FirstNameField(),
        const SizedBox(height: 16),
        LastNameField(),
      ],
    );
  },
)




19. Adaptive Login UI


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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Center(
          child: SingleChildScrollView(
            padding: const EdgeInsets.all(24),
            child: ConstrainedBox(
              constraints: const BoxConstraints(
                maxWidth: 450,
              ),
              child: Column(
                children: [
                  const FlutterLogo(size: 90),
                  const SizedBox(height: 24),
                  const Text(
                    'Welcome Back',
                    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'),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}




20. List-Detail Layout


A list-detail layout is especially useful on tablets and desktops.


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 this type of layout: large screens can show groups and details side-by-side, while smaller screens can navigate between them. Flutter List-Detail Adaptive Layout Tutorial




21. Desktop Sidebar


Row(
  children: [
    SizedBox(
      width: 250,
      child: Container(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            const Text(
              'My App',
              style: TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.bold,
              ),
            ),
            ListTile(
              leading: const Icon(Icons.dashboard),
              title: const Text('Dashboard'),
              onTap: () {},
            ),
            ListTile(
              leading: const Icon(Icons.people),
              title: const Text('Users'),
              onTap: () {},
            ),
            ListTile(
              leading: const Icon(Icons.settings),
              title: const Text('Settings'),
              onTap: () {},
            ),
          ],
        ),
      ),
    ),
    const VerticalDivider(width: 1),
    const Expanded(
      child: MainContent(),
    ),
  ],
)



22. Avoid Excessive Width on Desktop


Large monitors provide a lot of horizontal space, but that does not mean every widget should stretch across the entire window.


Use a maximum width for forms, articles, dialogs, and other content where excessive width would reduce readability.


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



23. Using Expanded and Flexible


Expanded


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

Flexible


Row(
  children: [
    Flexible(
      child: Text(
        'A long piece of text that can shrink when space is limited.',
      ),
    ),
    const Icon(Icons.info),
  ],
)

These widgets help prevent unnecessary fixed dimensions and allow layouts to use available space more effectively.




24. SafeArea


SafeArea helps keep important content away from areas affected by system UI and display cutouts.


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

This is especially useful on mobile devices where status bars, navigation areas, display cutouts, and rounded corners can affect usable space.




25. Supporting Orientation Changes


Applications should be prepared for changes in available width and height. A mobile application may change from portrait to landscape, and desktop or tablet applications may be resized continuously.


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

    return isWide
        ? const WideLayout()
        : const NarrowLayout();
  },
)


Width-based layout decisions are often preferable to relying only on orientation. Flutter's best-practice guidance also recommends avoiding unnecessary orientation locks. Flutter Adaptive Best Practices




26. Supporting Mouse and Keyboard on Desktop


Desktop applications should not depend exclusively on touch interaction. Users may expect mouse hover, keyboard navigation, shortcuts, scrolling, and pointer interactions.


Example Tooltip


Tooltip(
  message: 'Open settings',
  child: IconButton(
    onPressed: () {},
    icon: const Icon(Icons.settings),
  ),
)

Example Keyboard Shortcut


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

Flutter's adaptive guidance recommends supporting different input devices, including mouse, trackpad, and keyboard interaction, particularly on larger devices. Input and Adaptive UI Best Practices




27. Platform-Specific UI Considerations


Although Flutter allows code sharing across platforms, platform conventions can still matter.



  • Mobile users expect touch-friendly controls.

  • Desktop users expect mouse and keyboard support.

  • Desktop users commonly expect hover feedback.

  • Keyboard shortcuts can improve desktop workflows.

  • Context menus can be useful on desktop.

  • Scrolling behavior may need to feel appropriate to the input device.

  • Platform-specific navigation and interaction conventions may need consideration.


Flutter's platform-idiom guidance recommends considering the conventions users expect on each platform while still maintaining a consistent application identity. Flutter Platform Idioms




28. Adaptive Dashboard Example


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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Dashboard'),
      ),
      body: LayoutBuilder(
        builder: (context, constraints) {
          if (constraints.maxWidth < 600) {
            return const MobileDashboard();
          }

          if (constraints.maxWidth < 1000) {
            return const TabletDashboard();
          }

          return const DesktopDashboard();
        },
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(16),
      children: const [
        DashboardCard(title: 'Users', value: '12,450'),
        DashboardCard(title: 'Orders', value: '3,240'),
        DashboardCard(title: 'Revenue', value: '₹8,45,000'),
      ],
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return GridView.count(
      padding: const EdgeInsets.all(24),
      crossAxisCount: 2,
      crossAxisSpacing: 16,
      mainAxisSpacing: 16,
      children: const [
        DashboardCard(title: 'Users', value: '12,450'),
        DashboardCard(title: 'Orders', value: '3,240'),
        DashboardCard(title: 'Revenue', value: '₹8,45,000'),
        DashboardCard(title: 'Pending', value: '128'),
      ],
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        const SizedBox(
          width: 240,
          child: Center(
            child: Text('Sidebar'),
          ),
        ),
        Expanded(
          child: GridView.count(
            padding: const EdgeInsets.all(32),
            crossAxisCount: 4,
            crossAxisSpacing: 20,
            mainAxisSpacing: 20,
            children: const [
              DashboardCard(title: 'Users', value: '12,450'),
              DashboardCard(title: 'Orders', value: '3,240'),
              DashboardCard(title: 'Revenue', value: '₹8,45,000'),
              DashboardCard(title: 'Pending', value: '128'),
            ],
          ),
        ),
      ],
    );
  }
}

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

  const DashboardCard({
    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),
            const SizedBox(height: 8),
            Text(
              value,
              style: const TextStyle(
                fontSize: 26,
                fontWeight: FontWeight.bold,
              ),
            ),
          ],
        ),
      ),
    );
  }
}




29. Creating a Reusable Responsive Builder


When many screens require the same mobile, tablet, and desktop breakpoints, a reusable widget can make the code cleaner.


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 < 1000) {
          return tablet;
        }

        return desktop;
      },
    );
  }
}


Usage


ResponsiveLayout(
  mobile: const MobileHomePage(),
  tablet: const TabletHomePage(),
  desktop: const DesktopHomePage(),
)



30. Creating a Shared Data Model


Adaptive applications should generally share the same data and business logic while changing the presentation.


class Product {
  final String name;
  final double price;
  final String category;

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

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


The same products data can be displayed using a mobile ListView, tablet GridView, or desktop multi-column layout.




31. Mobile, Tablet and Desktop Architecture


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

This type of structure is optional. For many applications, it is preferable to keep shared widgets and data together and only separate the parts whose presentation truly differs.




32. Do Not Duplicate the Entire Application


A common beginner mistake is creating three completely independent applications:


MobileApp()
TabletApp()
DesktopApp()

This can create unnecessary duplication.


A better approach is:


Shared Data
     |
     +---- Shared Business Logic
     |
     +---- Shared Components
     |
     +---- Mobile Presentation
     +---- Tablet Presentation
     +---- Desktop Presentation

Flutter's adaptive guidance recommends abstracting shared data and breaking complex widgets into smaller reusable components. Flutter Adaptive Architecture Guidance




33. Common Mistakes


Mistake 1: Checking Only Device Type


if (isTablet) {
  return TabletLayout();
}

Physical device type does not always tell you how much space your application currently has. A tablet can run an app in a narrow multi-window configuration, and a desktop browser can be resized to a small window.


Mistake 2: Using Fixed Width Everywhere


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

This can cause overflow on smaller windows.


Mistake 3: Making Desktop Content Full Width


Large screens do not mean every text field, paragraph, or card should stretch across the entire window.


Mistake 4: Using Too Many Breakpoints


Too many layout branches can make an application difficult to maintain. Use breakpoints where the structure actually needs to change.


Mistake 5: Ignoring Input Methods


A desktop interface should not depend exclusively on touch gestures.


Mistake 6: Ignoring Orientation and Resizing


Applications should be tested when the available window changes.




34. Best Practices



  • Design for available space rather than physical device categories.

  • Use MediaQuery.sizeOf for application-window decisions.

  • Use LayoutBuilder for local widget constraints.

  • Choose breakpoints based on content requirements.

  • Use flexible layouts with Expanded and Flexible.

  • Use GridView for appropriate large-screen content.

  • Use ConstrainedBox to limit excessive desktop widths.

  • Use SafeArea for content that needs protection from system UI.

  • Use mobile-friendly touch targets.

  • Support mouse and keyboard interaction on desktop.

  • Use navigation patterns appropriate to available space.

  • Keep application state when the window changes size.

  • Break complex widgets into smaller reusable components.

  • Test Flutter Web by resizing the browser window.

  • Test portrait and landscape configurations.

  • Test different text sizes and accessibility settings.




35. Testing Mobile, Tablet and Desktop UI


Mobile Testing



  • Check portrait mode.

  • Check landscape mode.

  • Test small and large phone widths.

  • Test touch interactions.

  • Check scrolling.

  • Check keyboard visibility with forms.

  • Check safe areas and display cutouts.


Tablet Testing



  • Test portrait and landscape.

  • Test multi-column layouts.

  • Test navigation rail.

  • Test split-screen or constrained windows.

  • Check content density.


Desktop Testing



  • Resize the application window.

  • Test mouse interactions.

  • Test keyboard navigation.

  • Test hover states.

  • Test scrollbars.

  • Test large displays.

  • Check maximum content width.




36. Adaptive UI Testing with Flutter Web


Flutter Web is particularly useful for testing adaptive layouts because the browser window can be resized continuously.


flutter run -d chrome

After launching the application, resize the browser from a narrow width to a large desktop width and observe how the UI changes.


Flutter's adaptive tutorial specifically demonstrates resizing a browser window to observe adaptive layout changes. Flutter Adaptive Layout Tutorial




37. Practical Project: Mobile, Tablet and Desktop Dashboard


Build a dashboard containing:



  • Dashboard statistics.

  • User list.

  • Product cards.

  • Orders table.

  • Search field.

  • Filters.

  • Navigation.

  • Profile section.


Mobile


AppBar
   |
Stats Cards
   |
Search
   |
Product List
   |
Recent Orders
   |
NavigationBar

Tablet


NavigationRail | Dashboard
               |
               +-- Stats Cards
               +-- Product Grid
               +-- Orders

Desktop


Sidebar | Dashboard Header
        |
        +-- Statistics
        |
        +-- Charts | Recent Orders
        |
        +-- Product Grid
        |
        +-- Detailed Table



38. Complete Adaptive Application Structure


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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Adaptive Flutter App',
      home: const AdaptiveHome(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: LayoutBuilder(
          builder: (context, constraints) {
            final width = constraints.maxWidth;

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

            if (width < 1000) {
              return const TabletHome();
            }

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

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

  @override
  Widget build(BuildContext context) {
    return const Center(
      child: Text('Mobile UI'),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return const Center(
      child: Text('Tablet UI'),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return const Center(
      child: Text('Desktop UI'),
    );
  }
}




39. Quick Revision Table


















ConceptPurpose
Mobile UIOptimized for limited space and touch interaction.
Tablet UIUses additional space for multi-column and split layouts.
Desktop UIUses larger windows and pointer/keyboard interactions.
Responsive DesignFits UI into available space.
Adaptive DesignChanges UI structure to remain usable in available space.
MediaQueryMeasures application-window information.
LayoutBuilderProvides parent constraints for local layout decisions.
NavigationBarUseful for navigation in smaller layouts.
NavigationRailUseful for wider layouts.
GridViewDisplays content in multiple columns.
ExpandedUses available remaining space.
FlexibleAllows a child to flex within available space.
ConstrainedBoxLimits maximum or minimum dimensions.
SafeAreaProtects content from system UI and display cutouts.



40. Practice Exercises



  1. Create a Flutter application with different mobile, tablet, and desktop layouts.

  2. Create a navigation system that uses NavigationBar on mobile and NavigationRail on larger layouts.

  3. Create a product list that changes into a grid on larger screens.

  4. Create a responsive login form.

  5. Create a dashboard with one-column mobile cards, two-column tablet cards, and four-column desktop cards.

  6. Create a list-detail interface that displays both panels on desktop.

  7. Create a sidebar that appears only on larger screens.

  8. Add mouse tooltips and keyboard shortcuts for desktop users.

  9. Run the project in Chrome and resize the browser to test adaptive behavior.

  10. Test the application in portrait and landscape modes.




41. Key Takeaways



  • Flutter supports building applications for mobile, tablet, desktop, and web from a shared codebase.

  • Mobile layouts generally prioritize vertical content and touch-friendly interaction.

  • Tablet layouts can use additional horizontal space for split views and multi-column content.

  • Desktop layouts can use sidebars, navigation rails, tables, toolbars, and multi-panel interfaces.

  • Responsive design helps UI fit into available space.

  • Adaptive design changes the UI structure when necessary to keep it usable.

  • MediaQuery.sizeOf is useful for application-window-level decisions.

  • LayoutBuilder is useful for widget-level layout decisions.

  • Breakpoints should be based on the UI's space requirements rather than only on device names.

  • Large screens should not simply receive a stretched mobile interface.

  • Desktop interfaces should support mouse, keyboard, trackpad, and appropriate pointer interactions.

  • Reusable widgets and shared data reduce code duplication.

  • Testing different window sizes is essential for adaptive Flutter applications.




42. Official Flutter Resources





43. 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 Course Demo Registration page.




Conclusion


Building Mobile, Tablet and Desktop UI in Flutter requires more than simply increasing or decreasing widget sizes. A professional Flutter application should adapt its navigation, content arrangement, grids, forms, dashboards, spacing, and interaction patterns according to the available space and platform context. Use MediaQuery and LayoutBuilder to measure space, establish meaningful breakpoints, and combine flexible widgets such as Expanded, Flexible, GridView, Wrap, ConstrainedBox, and SafeArea. By sharing data and business logic while adapting presentation where appropriate, you can build one maintainable Flutter application that provides a usable experience across mobile, tablet, and desktop environments.


whatsapp