Flutter Responsive UI
Building adaptive layouts for all screen sizes
📱 What is Responsive UI?
Responsive UI adapts your app's layout to different screen sizes and orientations, from small phones to large tablets. Flutter provides powerful tools like MediaQuery, LayoutBuilder, and flexible widgets to create interfaces that look perfect on any device, ensuring optimal user experience across all platforms and screen dimensions.
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return DesktopLayout();
} else {
return MobileLayout();
}
},
)
Output:
Responsive Techniques
MediaQuery
Get screen size and orientation
double width =
MediaQuery.of(context)
.size.width;
LayoutBuilder
Build based on parent constraints
LayoutBuilder(
builder: (context, constraints) {
return Container(...);
},
)
Flexible & Expanded
Adaptive sizing in rows/columns
Expanded(
flex: 2,
child: Container(...),
)
AspectRatio
Maintain proportions
AspectRatio(
aspectRatio: 16 / 9,
child: Container(...),
)
🔹 Using MediaQuery
Get screen dimensions and adapt your layout:
import 'package:flutter/material.dart';
class ResponsiveWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Get screen size
double screenWidth = MediaQuery.of(context).size.width;
double screenHeight = MediaQuery.of(context).size.height;
// Get orientation
Orientation orientation = MediaQuery.of(context).orientation;
return Container(
width: screenWidth * 0.8, // 80% of screen width
height: screenHeight * 0.5, // 50% of screen height
color: Colors.blue,
child: Center(
child: Text(
'Width: ${screenWidth.toInt()}\n'
'Height: ${screenHeight.toInt()}\n'
'Orientation: $orientation',
style: TextStyle(color: Colors.white, fontSize: 16),
textAlign: TextAlign.center,
),
),
);
}
}
Output:
Height: 568
Orientation: portrait
🔹 LayoutBuilder for Breakpoints
Create different layouts based on available space:
class ResponsiveLayout extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
// Mobile layout (< 600px)
if (constraints.maxWidth < 600) {
return Column(
children: [
Container(height: 200, color: Colors.red),
Container(height: 200, color: Colors.green),
Container(height: 200, color: Colors.blue),
],
);
}
// Tablet/Desktop layout (>= 600px)
else {
return Row(
children: [
Expanded(child: Container(color: Colors.red)),
Expanded(child: Container(color: Colors.green)),
Expanded(child: Container(color: Colors.blue)),
],
);
}
},
);
}
}
Output:
🔹 Flexible and Expanded Widgets
Create flexible layouts that adapt to available space:
Row(
children: [
// Takes 1/4 of available space
Expanded(
flex: 1,
child: Container(
height: 100,
color: Colors.red,
child: Center(child: Text('1')),
),
),
// Takes 2/4 of available space
Expanded(
flex: 2,
child: Container(
height: 100,
color: Colors.green,
child: Center(child: Text('2')),
),
),
// Takes 1/4 of available space
Expanded(
flex: 1,
child: Container(
height: 100,
color: Colors.blue,
child: Center(child: Text('1')),
),
),
],
)
Output:
🔹 Responsive Grid
Create grids that adapt to screen size:
class ResponsiveGrid extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
// Calculate columns based on width
int columns = constraints.maxWidth > 600 ? 4 : 2;
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 1,
),
itemCount: 8,
itemBuilder: (context, index) {
return Container(
color: Colors.primaries[index % Colors.primaries.length],
child: Center(
child: Text(
'${index + 1}',
style: TextStyle(color: Colors.white, fontSize: 24),
),
),
);
},
);
},
);
}
}
Output:
🔹 Responsive Text Sizing
Scale text based on screen size:
class ResponsiveText extends StatelessWidget {
@override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
// Calculate responsive font size
double fontSize = screenWidth > 600 ? 32 : 20;
return Text(
'Responsive Text',
style: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
),
);
}
}
// Or use percentage of screen width
double responsiveFontSize(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
return screenWidth * 0.05; // 5% of screen width
}
Output:
🔹 Responsive Best Practices
Design Guidelines:
- Breakpoints: Use 600px for mobile/tablet, 900px for tablet/desktop
- Test on devices: Always test on real devices and emulators
- Flexible layouts: Use Expanded and Flexible instead of fixed sizes
- Orientation: Handle both portrait and landscape modes
- Safe areas: Use SafeArea widget for notches and system UI
- Minimum sizes: Set minimum tap targets of 48x48 pixels
// Common breakpoints
bool isMobile(BuildContext context) {
return MediaQuery.of(context).size.width < 600;
}
bool isTablet(BuildContext context) {
double width = MediaQuery.of(context).size.width;
return width >= 600 && width < 900;
}
bool isDesktop(BuildContext context) {
return MediaQuery.of(context).size.width >= 900;
}
// Responsive padding
double responsivePadding(BuildContext context) {
double width = MediaQuery.of(context).size.width;
if (width < 600) return 16;
if (width < 900) return 24;
return 32;
}