Flutter Responsive Layout

Building apps that adapt to any screen size

📱 What is Responsive Layout?

Responsive layout in Flutter means creating interfaces that adapt beautifully to different screen sizes and orientations. Your app looks great on phones, tablets, and desktops by adjusting layouts dynamically based on available space.


// Simple responsive example
LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth > 600) {
      return DesktopLayout();
    }
    return MobileLayout();
  },
)
                                    

Output:

Mobile: Single Column
Content 1
Content 2

Key Responsive Concepts

📐

MediaQuery

Get screen size information

MediaQuery.of(context)
  .size.width
🏗️

LayoutBuilder

Build based on constraints

LayoutBuilder(
  builder: (context, constraints) {},
)
🔄

OrientationBuilder

Adapt to orientation changes

OrientationBuilder(
  builder: (context, orientation) {},
)
📏

Flexible/Expanded

Proportional sizing

Flexible(
  flex: 1,
  child: Widget(),
)

🔹 Using MediaQuery

Get screen dimensions and adapt your layout:

import 'package:flutter/material.dart';

class ResponsiveExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final screenWidth = MediaQuery.of(context).size.width;
    final screenHeight = MediaQuery.of(context).size.height;
    
    return Scaffold(
      appBar: AppBar(title: Text('Responsive Layout')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Screen Width: ${screenWidth.toStringAsFixed(0)}'),
            Text('Screen Height: ${screenHeight.toStringAsFixed(0)}'),
            SizedBox(height: 20),
            Container(
              width: screenWidth * 0.8,
              height: 100,
              color: Colors.blue,
              child: Center(child: Text('80% Width')),
            ),
          ],
        ),
      ),
    );
  }
}

Output:

Screen Width: 400
Screen Height: 800
80% Width

🔹 LayoutBuilder for Breakpoints

Create different layouts based on screen width:

LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth > 800) {
      // Desktop layout
      return Row(
        children: [
          Expanded(child: Sidebar()),
          Expanded(flex: 3, child: MainContent()),
        ],
      );
    } else if (constraints.maxWidth > 600) {
      // Tablet layout
      return Column(
        children: [
          Container(height: 100, child: Sidebar()),
          Expanded(child: MainContent()),
        ],
      );
    } else {
      // Mobile layout
      return Column(
        children: [
          Expanded(child: MainContent()),
        ],
      );
    }
  },
)

Output (Mobile):

Main Content

🔹 OrientationBuilder

Adapt layout based on device orientation:

OrientationBuilder(
  builder: (context, orientation) {
    return GridView.count(
      crossAxisCount: orientation == Orientation.portrait ? 2 : 4,
      children: List.generate(
        12,
        (index) => Card(
          child: Center(child: Text('Item $index')),
        ),
      ),
    );
  },
)

Output (Portrait - 2 columns):

Item 0
Item 1
Item 2
Item 3

🔹 Responsive Text Sizing

Scale text based on screen size:

class ResponsiveText extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final screenWidth = MediaQuery.of(context).size.width;
    
    double fontSize = screenWidth > 600 ? 32 : 24;
    
    return Text(
      'Responsive Text',
      style: TextStyle(
        fontSize: fontSize,
        fontWeight: FontWeight.bold,
      ),
    );
  }
}

Output:

Responsive Text
Font size: 24px (mobile)

🔹 Responsive Padding and Spacing

Adjust spacing based on screen size:

class ResponsivePadding extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final screenWidth = MediaQuery.of(context).size.width;
    
    double padding = screenWidth > 600 ? 32.0 : 16.0;
    
    return Container(
      padding: EdgeInsets.all(padding),
      child: Column(
        children: [
          Text('Content with responsive padding'),
          SizedBox(height: padding),
          ElevatedButton(
            onPressed: () {},
            child: Text('Button'),
          ),
        ],
      ),
    );
  }
}

Output:

Content with responsive padding

🔹 Complete Responsive Example

Combine techniques for a fully responsive layout:

class ResponsiveHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Responsive App')),
      body: LayoutBuilder(
        builder: (context, constraints) {
          if (constraints.maxWidth > 800) {
            return _buildDesktopLayout();
          } else if (constraints.maxWidth > 600) {
            return _buildTabletLayout();
          } else {
            return _buildMobileLayout();
          }
        },
      ),
    );
  }
  
  Widget _buildMobileLayout() {
    return ListView(
      padding: EdgeInsets.all(16),
      children: [
        _buildCard('Card 1'),
        _buildCard('Card 2'),
        _buildCard('Card 3'),
      ],
    );
  }
  
  Widget _buildCard(String title) {
    return Card(
      margin: EdgeInsets.only(bottom: 16),
      child: Padding(
        padding: EdgeInsets.all(16),
        child: Text(title),
      ),
    );
  }
}

Output:

Card 1
Card 2
Card 3

🧠 Test Your Knowledge

Which widget provides screen size information?