Building Responsive UIs
1. Using MediaQuery Class
| Property | Description | Values |
|---|---|---|
| MediaQuery.of(context) | Retrieves the current media properties | MediaQueryData |
| size | Gets the size of the screen | Size |
| orientation | Gets the screen orientation | Orientation.portrait or Orientation.landscape |
| padding | Gets the padding for the screen (e.g., status bar, navigation bar) | EdgeInsets |
| textScaleFactor | Gets the current text scale factor | double |
Example: Using MediaQuery to get screen size
import 'package:flutter/material.dart';
class ResponsiveScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text(
"Screen size: ${MediaQuery.of(context).size.width} x ${MediaQuery.of(context).size.height}",
),
),
);
}
}
Note: MediaQuery is a powerful tool for building responsive UIs in Flutter. It provides access to various screen properties that can be used to adjust layouts dynamically.
2. Using LayoutBuilder Widget
The LayoutBuilder widget is a powerful tool for creating responsive UIs in Flutter. It allows you to build layouts that adapt based on the available space provided by its parent.
| Property | Description | Values |
|---|---|---|
| builder | The callback that builds the widget tree using the constraints provided by the parent. | Widget Function(BuildContext, BoxConstraints) |
Example: Using LayoutBuilder to adapt layout based on screen size
<div class="example">
<h3>Example: Using LayoutBuilder to adapt layout based on screen size</h3>
<div class="codeBlock" data-language="dart">
<pre><code>import 'package:flutter/material.dart';
class ResponsiveLayout extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return Column(
children: [
Text('Mobile View'),
Text('Content here'),
],
);
} else {
return Row(
children: [
Text('Desktop View'),
Text('Content here'),
],
);
}
},
);
}
}</code></pre>
</div>
</div>
3. Using OrientationBuilder Widget
| Property | Description | Usage |
|---|---|---|
| orientation | The current device orientation (portrait or landscape) | Orientation.portrait or Orientation.landscape |
Example: Using OrientationBuilder
OrientationBuilder(
builder: (context, orientation) {
return Container(
color: orientation == Orientation.portrait
? Colors.blue
: Colors.green,
child: Center(
child: Text(
"Orientation: ${orientation.name}",
),
),
);
},
)
Note: OrientationBuilder rebuilds the widget whenever the device orientation changes.
4. Creating Breakpoint-Based Layouts
| Breakpoint | Device Type | Width Range (px) | Usage |
|---|---|---|---|
| xs | Mobile | < 600 | Small mobile screens, portrait mode |
| sm | Mobile | 600 - 959 | Portrait and landscape mobile |
| md | Tablet | 960 - 1279 | Tablet in portrait or landscape |
| lg | Desktop | 1280 - 1919 | Desktop and large screens |
| xl | Large Desktop | >= 1920 | Very large screens, ultra-wide displays |
Example: Using Breakpoints in Layout
import 'package:flutter/material.dart';
class ResponsiveLayout extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return Text("Mobile View");
} else if (constraints.maxWidth < 960) {
return Text("Tablet View");
} else {
return Text("Desktop View");
}
},
);
}
}
Example: Responsive Grid with Breakpoints
import 'package:flutter/material.dart';
class ResponsiveGrid extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GridView.count(
crossAxisCount: MediaQuery.of(context).size.width < 600 ? 1 : 2,
children: List.generate(4, (index) {
return Card(
child: Center(child: Text("Item $index")),
);
}),
);
}
}
Note: Use
LayoutBuilder for more complex responsive logic that depends on the parent's constraints rather than screen size.
5. Using ResponsiveBuilder Patterns
The ResponsiveBuilder is a powerful widget in Flutter that allows you to build responsive UIs by detecting the screen size and adjusting the layout accordingly. It provides a clean way to adapt your UI based on different device types (mobile, tablet, desktop).
| Property | Description | Values |
|---|---|---|
| builder | The builder function that returns the widget to be built based on screen size. | Function<BuildContext, ScreenSize> → Widget |
| breakpoints | Custom breakpoints to define screen size ranges. | Map<String, BoxConstraints> |
Example: Basic ResponsiveBuilder Usage
ResponsiveBuilder(
builder: (context, sizingInformation) {
if (sizingInformation.screenSize == ScreenSize.small) {
return Text('Small screen');
} else if (sizingInformation.screenSize == ScreenSize.medium) {
return Text('Medium screen');
} else {
return Text('Large screen');
}
},
)
Example: Using Breakpoints
ResponsiveBuilder(
breakpoints: {
'mobile': const BoxConstraints(maxWidth: 600),
'tablet': const BoxConstraints(minWidth: 601, maxWidth: 1024),
'desktop': const BoxConstraints(minWidth: 1025),
},
builder: (context, sizingInformation) {
return Text('Current size: ${sizingInformation.screenSize}');
},
)
Note: The
ResponsiveBuilder uses LayoutBuilder internally to determine screen size, so it's reactive to changes in device orientation or window size.
Key Features of ResponsiveBuilder
- Automatically detects screen size categories (small, medium, large)
- Supports custom breakpoints for fine-grained control
- Provides
ScreenSizeenum to identify current screen size - Works with any widget tree inside the builder function
6. Using Flexible and Expanded Widgets
| Widget | Description | Usage |
|---|---|---|
| Flexible | Allows a child of a Row, Column, or Stack to expand and fill the available space. |
|
| Expanded | Similar to Flexible but takes up all available space in the parent's main axis direction. | |
Example: Flexible and Expanded in a Row
Row(
children: [
Container(
color: Colors.green,
width: 100,
),
Flexible(
child: Container(
color: Colors.blue,
height: 100,
),
),
Expanded(
child: Container(
color: Colors.red,
height: 100,
),
),
],
)
Note:
Flexible allows its child to expand and shrink, while Expanded forces its child to fill the available space.7. Creating Adaptive Layouts
| Property | Description | Values |
|---|---|---|
| LayoutBuilder | Builds a widget tree based on the available layout constraints | Widget build(BuildContext context) |
| MediaQuery | Provides information about the current device's screen size and orientation | MediaQueryData data = MediaQuery.of(context) |
| Orientation | Represents the screen orientation (portrait or landscape) | Orientation.portrait, Orientation.landscape |
| Breakpoint | Defines screen size thresholds for adaptive layouts | Breakpoint.small, Breakpoint.medium, Breakpoint.large |
Example: Using LayoutBuilder
class AdaptiveLayout extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return Column(
children: [
Text('Mobile View'),
Text('Content here'),
],
);
} else {
return Row(
children: [
Text('Desktop View'),
Text('Content here'),
],
);
}
},
);
}
}
Example: Using MediaQuery
class ResponsiveWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final orientation = MediaQuery.of(context).orientation;
return Container(
child: orientation == Orientation.portrait
? Text('Portrait Mode')
: Text('Landscape Mode'),
);
}
}
Note: LayoutBuilder is preferred over MediaQuery for adaptive layouts because it responds to changes in constraints rather than screen size alone.
8. Using Platform-Specific Widgets
| Widget | Description | Platform Support |
|---|---|---|
| MaterialApp | Flutter's Material Design implementation for Android and web. | Android Web |
| CupertinoApp | Flutter's iOS-style Cupertino widgets for iOS and web. | iOS Web |
| PlatformWidget | Allows custom rendering based on the platform. | All |
Example: Platform-Specific Widget Usage
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
Widget build(BuildContext context) {
return PlatformWidget(
android: (context) => MaterialButton(
onPressed: () {},
child: Text("Android Button"),
),
ios: (context) => CupertinoButton(
onPressed: () {},
child: Text("iOS Button"),
),
);
}
Note: Use
defaultTargetPlatform to detect the current platform in code.Platform-Specific Widget Summary
- MaterialApp is used for Material Design on Android and web.
- CupertinoApp is used for iOS-style widgets on iOS and web.
- PlatformWidget allows conditional rendering based on platform.
9. Implementing Responsive Text Sizes
| Property | Values | Description |
|---|---|---|
| TextTheme.displayLarge | TextStyle(fontSize: 96.0) |
Large display text for headlines |
| TextTheme.displayMedium | TextStyle(fontSize: 60.0) |
Medium display text |
| TextTheme.displaySmall | TextStyle(fontSize: 48.0) |
Small display text |
| TextTheme.headlineLarge | TextStyle(fontSize: 32.0) |
Large headline text |
| TextTheme.headlineMedium | TextStyle(fontSize: 24.0) |
Medium headline text |
| TextTheme.headlineSmall | TextStyle(fontSize: 20.0) |
Small headline text |
| TextTheme.titleLarge | TextStyle(fontSize: 20.0) |
Large title text |
| TextTheme.titleMedium | TextStyle(fontSize: 16.0) |
Medium title text |
| TextTheme.titleSmall | TextStyle(fontSize: 14.0) |
Small title text |
| TextTheme.bodyLarge | TextStyle(fontSize: 16.0) |
Large body text |
| TextTheme.bodyMedium | TextStyle(fontSize: 14.0) |
Medium body text |
| TextTheme.bodySmall | TextStyle(fontSize: 12.0) |
Small body text |
Example: Using Responsive Text in Flutter
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Responsive Text Demo',
theme: ThemeData(
useMaterial3: true,
textTheme: const TextTheme(
headlineLarge: TextStyle(fontSize: 32.0),
titleMedium: TextStyle(fontSize: 16.0),
bodyLarge: TextStyle(fontSize: 14.0),
),
),
home: Scaffold(
appBar: AppBar(title: Text("Responsive Text Example")),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Headline Large", style: Theme.of(context).textTheme.headlineLarge),
SizedBox(height: 10),
Text("Title Medium", style: Theme.of(context).textTheme.titleMedium),
SizedBox(height: 10),
Text("Body Large", style: Theme.of(context).textTheme.bodyLarge),
],
),
),
),
);
}
}
Note: Use
TextTheme to define consistent text styles across your app. Flutter provides built-in text themes that adapt to different screen sizes and device configurations.
10. Testing Different Screen Sizes
Example: Using Flutter's Device Preview
import 'package:flutter/material.dart';
import 'package:device_preview/device_preview.dart';
void main() {
runApp(
DevicePreview(
enabled: true,
builder: (context) => MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
useRootNavigator: false,
home: Scaffold(
appBar: AppBar(title: Text('Responsive UI')),
body: Center(child: Text('Hello, Flutter!')),
),
);
}
}
| Device | Screen Size (px) | Pixel Ratio | Notes |
|---|---|---|---|
| iPhone SE (2nd gen) | 375 x 667 |
2.0 |
Small screen, 16:9 aspect ratio |
| iPhone 12 Pro Max | 428 x 926 |
3.0 |
Large screen, 19:9 aspect ratio |
| iPad Air | 834 x 1194 |
2.0 |
Tablet, 4:3 aspect ratio |
| Samsung Galaxy S21 | 360 x 800 |
3.0 |
Android, 16:9 aspect ratio |
Note: Use
MediaQuery to dynamically adjust layout based on screen size.