When building responsive layouts in Flutter, two important widgets often come into play: Expanded and Flexible. These widgets allow developers to control how child widgets behave inside Row
, Column
, or Flex
layouts. Understanding the difference between them is crucial for creating adaptive UI designs that work across various screen sizes. In this article, we will explore what Expanded and Flexible widgets are, how they differ, and provide practical examples with source code you can directly use in your Flutter projects.
What is the Expanded Widget?
The Expanded widget in Flutter forces a child of a Row, Column, or Flex to expand and fill the available space along the main axis. Expanded takes as much space as possible, depending on the flex
property value. By default, flex: 1
.
Example of Expanded:
import 'package:flutter/material.dart'; void main() { runApp(MyExpandedExample()); } class MyExpandedExample extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('Expanded Example')), body: Row( children: [ Expanded( flex: 2, child: Container( color: Colors.red, child: Center(child: Text('Expanded Flex 2')), ), ), Expanded( flex: 1, child: Container( color: Colors.blue, child: Center(child: Text('Expanded Flex 1')), ), ), ], ), ), ); } }
In this example, the red container takes twice the space of the blue container because its flex
value is 2 while the other is 1.
What is the Flexible Widget?
The Flexible widget gives its child the flexibility to either fill the available space or keep its natural size, depending on the fit
property. The fit
property can be either FlexFit.tight
or FlexFit.loose
.
- FlexFit.tight: Forces the child to fill the available space (similar to Expanded).
- FlexFit.loose: Lets the child occupy only as much space as it needs.
Example of Flexible:
import 'package:flutter/material.dart'; void main() { runApp(MyFlexibleExample()); } class MyFlexibleExample extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('Flexible Example')), body: Row( children: [ Flexible( flex: 1, fit: FlexFit.tight, child: Container( color: Colors.green, child: Center(child: Text('Tight Flexible')), ), ), Flexible( flex: 1, fit: FlexFit.loose, child: Container( color: Colors.orange, width: 100, child: Center(child: Text('Loose Flexible')), ), ), ], ), ), ); } }
Here, the green box behaves like an Expanded widget because it uses FlexFit.tight
, while the orange box keeps its natural width due to FlexFit.loose
.
Comparison Between Expanded and Flexible
Although Expanded is essentially a shortcut for Flexible(fit: FlexFit.tight)
, it is often used for simplicity. Flexible, however, provides more customization because you can choose between tight and loose fitting.
Property | Expanded | Flexible |
---|---|---|
Default Fit | Always tight | Can be tight or loose |
Space Usage | Fills all available space | Can fill or keep natural size |
Flex Control | Yes, via flex | Yes, via flex + fit |
Use Case | When child must expand fully | When child may expand or stay natural |
Practical Use Case Example
Let’s consider a case where you want to create a layout with a header, a body section that expands, and a footer that only takes as much space as needed. Here is how you can achieve that using Expanded and Flexible together.
import 'package:flutter/material.dart'; void main() { runApp(MyUseCaseExample()); } class MyUseCaseExample extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('Expanded vs Flexible')), body: Column( children: [ Container( color: Colors.purple, height: 60, child: Center(child: Text('Header - Fixed Size')), ), Expanded( flex: 3, child: Container( color: Colors.yellow, child: Center(child: Text('Body - Expanded')), ), ), Flexible( flex: 1, fit: FlexFit.loose, child: Container( color: Colors.grey, height: 80, child: Center(child: Text('Footer - Flexible Loose')), ), ), ], ), ), ); } }
In this example:
- The header has a fixed height.
- The body expands to take up most of the available space.
- The footer only takes the space it needs, thanks to Flexible with
FlexFit.loose
.
Conclusion
Understanding the differences between Expanded and Flexible widgets in Flutter is key for building responsive and adaptive UI layouts. Expanded always forces its child to occupy available space, while Flexible provides more control with tight
and loose
fitting. By combining these two widgets, you can achieve a wide variety of layout behaviors for your mobile apps.
For more details about layout widgets in Flutter, you can also check the official documentation at Flutter Layout Widgets.