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:
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:
🔹 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):
🔹 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):
🔹 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 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:
🔹 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),
),
);
}
}