In Flutter, building responsive and adaptable user interfaces requires understanding how widgets can interact and resize within their parent layouts. The Expanded
and Flexible
widgets are fundamental tools for managing how child widgets occupy space in Row
and Column
layouts. This in-depth exploration covers the purpose, usage, differences, and practical examples of Expanded
and Flexible
widgets in Flutter.
Understanding Expanded and Flexible Widgets in Flutter
The Expanded
and Flexible
widgets are layout widgets that control how a child widget occupies available space along the main axis of a Row
or Column
. They allow you to define how much space a widget should take up relative to other widgets, helping create responsive layouts that adapt to different screen sizes.
What is the Expanded
Widget?
The Expanded
widget forces its child to fill the available space in the main axis of a Row
or Column
. The remaining space is distributed among the expanded widgets according to their flex factor. If no flex factor is specified, it defaults to 1, meaning all Expanded
widgets will share the available space equally.
What is the Flexible
Widget?
The Flexible
widget is similar to Expanded
, but it doesn’t force its child to fill the available space completely. Instead, the Flexible
widget allows its child to be as big as it wants, but no bigger than the available space. It also uses a flex factor to distribute remaining space among Flexible
widgets.
Why Use Expanded
and Flexible
?
- Responsive Layouts: Dynamically adjust the size of widgets based on screen size.
- Space Distribution: Control how space is distributed among multiple widgets.
- Adaptable UI: Create UIs that look good on different devices and orientations.
How to Use Expanded
and Flexible
in Flutter
Using Expanded
Here’s an example of using the Expanded
widget to distribute space equally among three containers in a Row
:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Expanded Example'),
),
body: Row(
children: <Widget>[
Expanded(
child: Container(
color: Colors.red,
child: Center(
child: Text('Red', style: TextStyle(color: Colors.white)),
),
),
),
Expanded(
child: Container(
color: Colors.green,
child: Center(
child: Text('Green', style: TextStyle(color: Colors.white)),
),
),
),
Expanded(
child: Container(
color: Colors.blue,
child: Center(
child: Text('Blue', style: TextStyle(color: Colors.white)),
),
),
),
],
),
),
);
}
}
In this example, each container occupies one-third of the available space in the Row
.
Using Expanded
with Different Flex Factors
Here’s how to use Expanded
with different flex factors:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Expanded with Flex Example'),
),
body: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
color: Colors.red,
child: Center(
child: Text('Red (Flex: 2)', style: TextStyle(color: Colors.white)),
),
),
),
Expanded(
flex: 1,
child: Container(
color: Colors.green,
child: Center(
child: Text('Green (Flex: 1)', style: TextStyle(color: Colors.white)),
),
),
),
Expanded(
flex: 1,
child: Container(
color: Colors.blue,
child: Center(
child: Text('Blue (Flex: 1)', style: TextStyle(color: Colors.white)),
),
),
),
],
),
),
);
}
}
In this case, the red container occupies half of the available space, while the green and blue containers each occupy one-quarter.
Using Flexible
Here’s an example of using the Flexible
widget. In this scenario, the intrinsic size of the widgets is respected, but they will not exceed the available space.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flexible Example'),
),
body: Row(
children: <Widget>[
Flexible(
child: Container(
color: Colors.red,
child: Text('Red: This text determines the size', style: TextStyle(color: Colors.white)),
),
),
Flexible(
child: Container(
color: Colors.green,
child: Text('Green', style: TextStyle(color: Colors.white)),
),
),
Flexible(
child: Container(
color: Colors.blue,
child: Text('Blue', style: TextStyle(color: Colors.white)),
),
),
],
),
),
);
}
}
In this example, the “Red” container adjusts its size based on the length of the text, while the other containers take up remaining space but respect their content’s size.
Using Flexible
with Different Flex Factors
Here’s how to use Flexible
with different flex factors. Like Expanded
, you can assign different flex factors to distribute available space among the widgets.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flexible with Flex Example'),
),
body: Row(
children: <Widget>[
Flexible(
flex: 2,
child: Container(
color: Colors.red,
child: Text('Red: This text determines the size', style: TextStyle(color: Colors.white)),
),
),
Flexible(
flex: 1,
child: Container(
color: Colors.green,
child: Text('Green', style: TextStyle(color: Colors.white)),
),
),
Flexible(
flex: 1,
child: Container(
color: Colors.blue,
child: Text('Blue', style: TextStyle(color: Colors.white)),
),
),
],
),
),
);
}
}
Key Differences Between Expanded
and Flexible
- Space Occupation:
Expanded
forces the child to fill available space, whileFlexible
allows the child to occupy space based on its content, up to the available space. - Behavior:
Expanded
ensures widgets fill available space, potentially stretching them.Flexible
is more adaptable to the intrinsic size of the content.
Practical Examples and Use Cases
Creating a Responsive Toolbar
Use Expanded
to create a toolbar where certain widgets take up equal space:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Responsive Toolbar'),
),
body: Row(
children: <Widget>[
IconButton(icon: Icon(Icons.menu), onPressed: () {}),
Expanded(
child: Center(child: Text('Title')),
),
IconButton(icon: Icon(Icons.search), onPressed: () {}),
],
),
),
);
}
}
In this example, the title is centered and takes up the available space between the menu and search icons.
Adaptive Chat Bubbles
Use Flexible
to create chat bubbles that adjust their width based on the message content:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Adaptive Chat Bubbles'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Flexible(
child: Container(
padding: EdgeInsets.all(8.0),
margin: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(8.0),
),
child: Text('Hello, how are you?'),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Flexible(
child: Container(
padding: EdgeInsets.all(8.0),
margin: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.blue[300],
borderRadius: BorderRadius.circular(8.0),
),
child: Text('I\'m doing great, thanks! How about you?', style: TextStyle(color: Colors.white)),
),
),
],
),
],
),
),
);
}
}
The chat bubbles adapt to the length of the message while respecting the available space in the layout.
Conclusion
Expanded
and Flexible
are essential widgets for building adaptive and responsive layouts in Flutter. Expanded
forces its child to fill available space, while Flexible
allows the child to adapt based on its content. By understanding the nuances of these widgets and using them appropriately, you can create user interfaces that provide an optimal experience across a variety of screen sizes and devices. Experiment with different flex factors and combinations of Expanded
and Flexible
to achieve the desired layout behavior.