Layout _ Flutter
Layout _ Flutter
Layouts in Flutter
UI chevron_right Layout
Contents keyboard_arrow_down
Lay out a widget
1. Select a layout widget
2. Create a visible widget
more_horiz
The core of Flutter's layout mechanism is widgets. In Flutter, almost everything is a widget—even layout models are widgets. The
images, icons, and text that you see in a Flutter app are all widgets. But things you don't see are also widgets, such as the rows,
columns, and grids that arrange, constrain, and align the visible widgets.
You create a layout by composing widgets to build more complex widgets. For example, the first screenshot below shows 3 icons
with a label under each one:
The second screenshot displays the visual layout, showing a row of 3 columns where each column contains an icon and a label.
info Note
Most of the screenshots in this tutorial are displayed with debugPaintSizeEnabled set to true so you can see the visual
layout. For more information, see Debugging layout issues visually, a section in Using the Flutter inspector.
https://docs.flutter.dev/ui/layout 1/24
12/29/24, 1:20 PM Layout | Flutter
Most of this should look as you might expect, but you might be wondering about the containers (shown in pink). Container is a
widget class that allows you to customize its child widget. Use a Container when you want to add padding, margins, borders, or
background color, to name some of its capabilities.
In this example, each Text widget is placed in a Container to add margins. The entire Row is also placed in a Container to add
padding around the row.
The rest of the UI in this example is controlled by properties. Set an Icon's color using its color property. Use the Text.style
property to set the font, its color, weight, and so on. Columns and rows have properties that allow you to specify how their
children are aligned vertically or horizontally, and how much space the children should occupy.
In Flutter, it takes only a few steps to put text, an icon, or an image on the screen.
This example uses Center which centers its content horizontally and vertically.
dart
Text('Hello World'),
dart
return Image.asset(
image,
fit: BoxFit.cover,
);
https://docs.flutter.dev/ui/layout 2/24
12/29/24, 1:20 PM Layout | Flutter
dart
Icon(
Icons.star,
color: Colors.red[500],
),
dart
const Center(
child: Text('Hello World'),
),
Material apps
For a Material app, you can use a Scaffold widget; it provides a default banner, background color, and has API for adding
drawers, snack bars, and bottom sheets. Then you can add the Center widget directly to the body property for the home page.
dart
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
const String appTitle = 'Flutter layout demo';
return MaterialApp(
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: const Text(appTitle),
),
body: const Center(
child: Text('Hello World'),
),
),
);
}
}
info Note
The Material library implements widgets that follow Material Design principles. When designing your UI, you can exclusively
use widgets from the standard widgets library, or you can use widgets from the Material library. You can mix widgets from
both libraries, you can customize existing widgets, or you can build your own set of custom widgets.
https://docs.flutter.dev/ui/layout 3/24
12/29/24, 1:20 PM Layout | Flutter
Cupertino apps
To create a Cupertino app, use CupertinoApp and CupertinoPageScaffold widgets.
Unlike Material, it doesn't provide a default banner or background color. You need to set these yourself.
To set default colors, pass in a configured CupertinoThemeData to your app's theme property.
To add an iOS-styled navigation bar to the top of your app, add a CupertinoNavigationBar widget to the navigationBar
property of your scaffold. You can use the colors that CupertinoColors provides to configure your widgets to match iOS
design.
To lay out the body of your app, set the child property of your scaffold with the desired widget as its value, like Center or
Column.
To learn what other UI components you can add, check out the Cupertino library.
dart
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const CupertinoApp(
title: 'Flutter layout demo',
theme: CupertinoThemeData(
brightness: Brightness.light,
primaryColor: CupertinoColors.systemBlue,
),
home: CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
backgroundColor: CupertinoColors.systemGrey,
middle: Text('Flutter layout demo'),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Hello World'),
],
),
),
),
);
}
}
info Note
The Cupertino library implements widgets that follow Apple's Human Interface Guidelines for iOS. When designing your UI,
you can use widgets from the standard widgets library, or the Cupertino library. You can mix widgets from both libraries, you
can customize existing widgets, or you can build your own set of custom widgets.
Non-Material apps
For a non-Material app, you can add the Container widget to the app's build() method:
https://docs.flutter.dev/ui/layout 4/24
12/29/24, 1:20 PM Layout | Flutter
dart
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return Container(
decoration: const BoxDecoration(color: Colors.white),
child: const Center(
child: Text(
'Hello World',
textDirection: TextDirection.ltr,
style: TextStyle(
fontSize: 32,
color: Colors.black87,
),
),
),
);
}
}
By default, a non-Material app doesn't include an AppBar, title, or background color. If you want these features in a non-Material
app, you have to build them yourself. This app changes the background color to white and the text to dark grey to mimic a
Material app.
That's it! When you run the app, you should see Hello World.
Material app
Non-Material app
To create a row or column in Flutter, you add a list of children widgets to a Row or Column widget. In turn, each child can itself be a
row or column, and so on. The following example shows how it is possible to nest rows or columns inside of rows or columns.
This layout is organized as a Row. The row contains two children: a column on the left, and an image on the right:
You'll implement some of Pavlova's layout code in Nesting rows and columns.
info Note
Row and Column are basic primitive widgets for horizontal and vertical layouts—these low-level widgets allow for maximum
customization. Flutter also offers specialized, higher level widgets that might be sufficient for your needs. For example,
instead of Row you might prefer ListTile, an easy-to-use widget with properties for leading and trailing icons, and up to 3
lines of text. Instead of Column, you might prefer ListView, a column-like layout that automatically scrolls if its content is
too long to fit the available space. For more information, see Common layout widgets.
https://docs.flutter.dev/ui/layout 6/24
12/29/24, 1:20 PM Layout | Flutter
Aligning widgets
You control how a row or column aligns its children using the mainAxisAlignment and crossAxisAlignment properties. For a row,
the main axis runs horizontally and the cross axis runs vertically. For a column, the main axis runs vertically and the cross axis runs
horizontally.
The MainAxisAlignment and CrossAxisAlignment enums offer a variety of constants for controlling alignment.
info Note
When you add images to your project, you need to update the pubspec.yaml file to access them—this example uses
Image.asset to display the images. For more information, see this example's pubspec.yaml file or Adding assets and
images. You don't need to do this if you're referencing online images using Image.network.
In the following example, each of the 3 images is 100 pixels wide. The render box (in this case, the entire screen) is more than 300
pixels wide, so setting the main axis alignment to spaceEvenly divides the free horizontal space evenly between, before, and after
each image.
dart
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset('images/pic1.jpg'),
Image.asset('images/pic2.jpg'),
Image.asset('images/pic3.jpg'),
],
);
Columns work the same way as rows. The following example shows a column of 3 images, each is 100 pixels high. The height of
the render box (in this case, the entire screen) is more than 300 pixels, so setting the main axis alignment to spaceEvenly divides
the free vertical space evenly between, above, and below each image.
dart
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset('images/pic1.jpg'),
Image.asset('images/pic2.jpg'),
Image.asset('images/pic3.jpg'),
],
);
https://docs.flutter.dev/ui/layout 7/24
12/29/24, 1:20 PM Layout | Flutter
Sizing widgets
When a layout is too large to fit a device, a yellow and black striped pattern appears along the affected edge. Here is an example
of a row that is too wide:
Widgets can be sized to fit within a row or column by using the Expanded widget. To fix the previous example where the row of
images is too wide for its render box, wrap each image with an Expanded widget.
dart
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Image.asset('images/pic1.jpg'),
),
Expanded(
child: Image.asset('images/pic2.jpg'),
),
Expanded(
child: Image.asset('images/pic3.jpg'),
),
],
);
https://docs.flutter.dev/ui/layout 8/24
12/29/24, 1:20 PM Layout | Flutter
Perhaps you want a widget to occupy twice as much space as its siblings. For this, use the Expanded widget flex property, an
integer that determines the flex factor for a widget. The default flex factor is 1. The following code sets the flex factor of the
middle image to 2:
dart
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Image.asset('images/pic1.jpg'),
),
Expanded(
flex: 2,
child: Image.asset('images/pic2.jpg'),
),
Expanded(
child: Image.asset('images/pic3.jpg'),
),
],
);
Packing widgets
By default, a row or column occupies as much space along its main axis as possible, but if you want to pack the children closely
together, set its mainAxisSize to MainAxisSize.min. The following example uses this property to pack the star icons together.
dart
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
const Icon(Icons.star, color: Colors.black),
const Icon(Icons.star, color: Colors.black),
],
)
https://docs.flutter.dev/ui/layout 9/24
12/29/24, 1:20 PM Layout | Flutter
The outlined section is implemented as two rows. The ratings row contains five stars and the number of reviews. The icons row
contains three columns of icons and text.
The ratings variable creates a row containing a smaller row of 5-star icons, and text:
https://docs.flutter.dev/ui/layout 10/24
12/29/24, 1:20 PM Layout | Flutter
dart
final stars = Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
const Icon(Icons.star, color: Colors.black),
const Icon(Icons.star, color: Colors.black),
],
);
lightbulb Tip
To minimize the visual confusion that can result from heavily nested layout code, implement pieces of the UI in variables and
functions.
The icons row, below the ratings row, contains 3 columns; each column contains an icon and two lines of text, as you can see in its
widget tree:
https://docs.flutter.dev/ui/layout 11/24
12/29/24, 1:20 PM Layout | Flutter
dart
const descTextStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 18,
height: 2,
);
The leftColumn variable contains the ratings and icons rows, as well as the title and text that describes the Pavlova:
https://docs.flutter.dev/ui/layout 12/24
12/29/24, 1:20 PM Layout | Flutter
dart
final leftColumn = Container(
padding: const EdgeInsets.fromLTRB(20, 30, 20, 20),
child: Column(
children: [
titleText,
subTitle,
ratings,
iconList,
],
),
);
The left column is placed in a SizedBox to constrain its width. Finally, the UI is constructed with the entire row (containing the left
column and the image) inside a Card.
The Pavlova image is from Pixabay. You can embed an image from the net using Image.network() but, for this example, the image
is saved to an images directory in the project, added to the pubspec file, and accessed using Images.asset(). For more
information, see Adding assets and images.
dart
body: Center(
child: Container(
margin: const EdgeInsets.fromLTRB(0, 40, 0, 30),
height: 600,
child: Card(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 440,
child: leftColumn,
),
mainImage,
],
),
),
),
),
lightbulb Tip
The Pavlova example runs best horizontally on a wide device, such as a tablet. If you are running this example in the iOS
simulator, you can select a different device using the Hardware > Device menu. For this example, we recommend the iPad
Pro. You can change its orientation to landscape mode using Hardware > Rotate. You can also change the size of the
simulator window (without changing the number of logical pixels) using Window > Scale.
https://docs.flutter.dev/ui/layout 13/24
12/29/24, 1:20 PM Layout | Flutter
The following widgets fall into two categories: standard widgets from the widgets library, and specialized widgets from the
Material library. Any app can use the widgets library but only Material apps can use the Material Components library.
Standard widgets
Container: Adds padding, margins, borders, background color, or other decorations to a widget.
GridView: Lays widgets out as a scrollable grid.
ListView: Lays widgets out as a scrollable list.
Stack: Overlaps a widget on top of another.
Material widgets
Card: Organizes related info into a box with rounded corners and a drop shadow.
ListTile: Organizes up to 3 lines of text, and optional leading and trailing icons, into a row.
Container
Many layouts make liberal use of Containers to separate widgets using padding, or to add borders or margins. You can change
the device's background by placing the entire layout into a Container and changing its background color or image.
Summary (Container)
Add padding, margins, borders
Change background color or image
Contains a single child widget, but that child can be a Row, Column, or even the root of a widget tree
Examples (Container)
This layout consists of a column with two rows, each containing 2 images. A Container is used to change the background color of
the column to a lighter grey.
dart
Widget _buildImageColumn() {
return Container(
decoration: const BoxDecoration(
color: Colors.black26,
),
child: Column(
children: [
_buildImageRow(1),
_buildImageRow(3),
],
),
);
}
https://docs.flutter.dev/ui/layout 14/24
12/29/24, 1:20 PM Layout | Flutter
A Container is also used to add a rounded border and margins to each image:
dart
Widget _buildDecoratedImage(int imageIndex) => Expanded(
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 10, color: Colors.black38),
borderRadius: const BorderRadius.all(Radius.circular(8)),
),
margin: const EdgeInsets.all(4),
child: Image.asset('images/pic$imageIndex.jpg'),
),
);
GridView
Use GridView to lay widgets out as a two-dimensional list. GridView provides two pre-fabricated lists, or you can build your own
custom grid. When a GridView detects that its contents are too long to fit the render box, it automatically scrolls.
Summary (GridView)
Lays widgets out in a grid
Detects when the column content exceeds the render box and automatically provides scrolling
Build your own custom grid, or use one of the provided grids:
GridView.count allows you to specify the number of columns
GridView.extent allows you to specify the maximum pixel width of a tile
info Note
When displaying a two-dimensional list where it's important which row and column a cell occupies (for example, it's the
entry in the "calorie" column for the "avocado" row), use Table or DataTable.
Examples (GridView)
https://docs.flutter.dev/ui/layout 15/24
12/29/24, 1:20 PM Layout | Flutter
Uses GridView.extent to create a grid with tiles a maximum 150 pixels wide.
Uses GridView.count to create a grid that's 2 tiles wide in portrait mode, and 3 tiles wide in landscape mode. The titles are
created by setting the footer property for each GridTile.
https://docs.flutter.dev/ui/layout 16/24
12/29/24, 1:20 PM Layout | Flutter
dart
Widget _buildGrid() => GridView.extent(
maxCrossAxisExtent: 150,
padding: const EdgeInsets.all(4),
mainAxisSpacing: 4,
crossAxisSpacing: 4,
children: _buildGridTileList(30));
ListView
ListView, a column-like widget, automatically provides scrolling when its content is too long for its render box.
Summary (ListView)
A specialized Column for organizing a list of boxes
Can be laid out horizontally or vertically
Detects when its content won't fit and provides scrolling
Less configurable than Column, but easier to use and supports scrolling
Examples (ListView)
Uses ListView to display a list of businesses using ListTiles. A Divider separates the theaters from the restaurants.
https://docs.flutter.dev/ui/layout 17/24
12/29/24, 1:20 PM Layout | Flutter
Uses ListView to display the Colors from the Material 2 Design palette for a particular color family.
https://docs.flutter.dev/ui/layout 18/24
12/29/24, 1:20 PM Layout | Flutter
dart
Widget _buildList() {
return ListView(
children: [
_tile('CineArts at the Empire', '85 W Portal Ave', Icons.theaters),
_tile('The Castro Theater', '429 Castro St', Icons.theaters),
_tile('Alamo Drafthouse Cinema', '2550 Mission St', Icons.theaters),
_tile('Roxie Theater', '3117 16th St', Icons.theaters),
_tile('United Artists Stonestown Twin', '501 Buckingham Way',
Icons.theaters),
_tile('AMC Metreon 16', '135 4th St #3000', Icons.theaters),
const Divider(),
_tile('K\'s Kitchen', '757 Monterey Blvd', Icons.restaurant),
_tile('Emmy\'s Restaurant', '1923 Ocean Ave', Icons.restaurant),
_tile('Chaiya Thai Restaurant', '272 Claremont Blvd', Icons.restaurant),
_tile('La Ciccia', '291 30th St', Icons.restaurant),
],
);
}
Stack
Use Stack to arrange widgets on top of a base widget—often an image. The widgets can completely or partially overlap the base
widget.
Summary (Stack)
Use for widgets that overlap another widget
The first widget in the list of children is the base widget; subsequent children are overlaid on top of that base widget
A Stack's content can't scroll
You can choose to clip children that exceed the render box
Examples (Stack)
https://docs.flutter.dev/ui/layout 19/24
12/29/24, 1:20 PM Layout | Flutter
Uses Stack to overlay a Container (that displays its Text on a translucent black background) on top of a CircleAvatar. The Stack
offsets the text using the alignment property and Alignments.
dart
Widget _buildStack() {
return Stack(
alignment: const Alignment(0.6, 0.6),
children: [
const CircleAvatar(
backgroundImage: AssetImage('images/pic.jpg'),
radius: 100,
),
Container(
decoration: const BoxDecoration(
color: Colors.black45,
),
child: const Text(
'Mia B',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
);
}
Card
A Card, from the Material library, contains related nuggets of information and can be composed from almost any widget, but is
often used with ListTile. Card has a single child, but its child can be a column, row, list, grid, or other widget that supports
multiple children. By default, a Card shrinks its size to 0 by 0 pixels. You can use SizedBox to constrain the size of a card.
https://docs.flutter.dev/ui/layout 20/24
12/29/24, 1:20 PM Layout | Flutter
In Flutter, a Card features slightly rounded corners and a drop shadow, giving it a 3D effect. Changing a Card's elevation property
allows you to control the drop shadow effect. Setting the elevation to 24, for example, visually lifts the Card further from the
surface and causes the shadow to become more dispersed. For a list of supported elevation values, see Elevation in the Material
guidelines. Specifying an unsupported value disables the drop shadow entirely.
Summary (Card)
Implements a Material card
Used for presenting related nuggets of information
Accepts a single child, but that child can be a Row, Column, or other widget that holds a list of children
Displayed with rounded corners and a drop shadow
A Card's content can't scroll
From the Material library
Examples (Card)
A Card containing 3 ListTiles and sized by wrapping it with a SizedBox. A Divider separates the first and second ListTiles.
https://docs.flutter.dev/ui/layout 21/24
12/29/24, 1:20 PM Layout | Flutter
dart
Widget _buildCard() {
return SizedBox(
height: 210,
child: Card(
child: Column(
children: [
ListTile(
title: const Text(
'1625 Main Street',
style: TextStyle(fontWeight: FontWeight.w500),
),
subtitle: const Text('My City, CA 99984'),
leading: Icon(
Icons.restaurant_menu,
color: Colors.blue[500],
),
),
const Divider(),
ListTile(
title: const Text(
'(408) 555-1212',
style: TextStyle(fontWeight: FontWeight.w500),
),
leading: Icon(
Icons.contact_phone,
color: Colors.blue[500],
),
),
ListTile(
title: const Text('costa@example.com'),
leading: Icon(
Icons.contact_mail,
color: Colors.blue[500],
),
),
],
),
),
);
}
ListTile
Use ListTile, a specialized row widget from the Material library, for an easy way to create a row containing up to 3 lines of text
and optional leading and trailing icons. ListTile is most commonly used in Card or ListView, but can be used elsewhere.
Summary (ListTile)
A specialized row that contains up to 3 lines of text and optional icons
Less configurable than Row, but easier to use
From the Material library
Examples (ListTile)
https://docs.flutter.dev/ui/layout 22/24
12/29/24, 1:20 PM Layout | Flutter
Constraints
To fully understand Flutter's layout system, you need to learn how Flutter positions and sizes the components in a layout. For
more information, see Understanding constraints.
Videos
The following videos, part of the Flutter in Focus series, explain Stateless and Stateful widgets.
Each episode of the Widget of the Week series focuses on a widget. Several of them includes layout widgets.
https://docs.flutter.dev/ui/layout 23/24
12/29/24, 1:20 PM Layout | Flutter
Other resources
The following resources might help when writing layout code.
Layout tutorial
Learn how to build a layout.
Widget catalog
Describes many of the widgets available in Flutter.
HTML/CSS Analogs in Flutter
For those familiar with web programming, this page maps HTML/CSS functionality to Flutter features.
API reference docs
Reference documentation for all of the Flutter libraries.
Adding assets and images
Explains how to add images and other assets to your app's package.
Zero to One with Flutter
One person's experience writing his first Flutter app.
https://docs.flutter.dev/ui/layout 24/24