Layout Tutorial _ Flutter
Layout Tutorial _ Flutter
Contents keyboard_arrow_down
Diagram the layout
Create the app base code
Add the Title section
more_horiz
If you use the example code provided, you can build the following app.
To get a better overview of the layout mechanism, start with Flutter's approach to layout.
Consider how to position the components of your user interface. A layout consists of the total end result of these positionings.
Consider planning your layout to speed up your coding. Using visual cues to know where something goes on screen can be a
great help.
Use whichever method you prefer, like an interface design tool or a pencil and a sheet of paper. Figure out where you want to
place elements on your screen before writing code. It's the programming version of the adage: "Measure twice, cut once."
1. Ask these questions to break the layout down to its basic elements.
https://docs.flutter.dev/ui/layout/tutorial 1/12
12/29/24, 1:21 PM Layout tutorial | Flutter
2. Identify the larger elements. In this example, you arrange the image, title, buttons, and description into a column.
Major elements in the layout: image, row, row, and text block
a. Row 1, the Title section, has three children: a column of text, a star icon, and a number. Its first child, the column,
contains two lines of text. That first column might need more space.
b. Row 2, the Button section, has three children: each child contains a column which then contains an icon and text.
After diagramming the layout, consider how you would code it.
Would you write all the code in one class? Or, would you create one class for each part of the layout?
To follow Flutter best practices, create one class, or Widget, to contain each part of your layout. When Flutter needs to re-render
part of a UI, it updates the smallest part that changes. This is why Flutter makes "everything a widget". If only the text changes in
a Text widget, Flutter redraws only that text. Flutter changes the least amount of the UI possible in response to user input.
For this tutorial, write each element you have identified as its own widget.
3. Replace the contents of lib/main.dart with the following code. This app uses a parameter for the app title and the title
shown on the app's appBar. This decision simplifies the code.
https://docs.flutter.dev/ui/layout/tutorial 2/12
12/29/24, 1:21 PM Layout tutorial | Flutter
dart
import 'package:flutter/material.dart';
@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'),
),
),
);
}
}
https://docs.flutter.dev/ui/layout/tutorial 3/12
12/29/24, 1:21 PM Layout tutorial | Flutter
dart
class TitleSection extends StatelessWidget {
const TitleSection({
super.key,
required this.name,
required this.location,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(32),
child: Row(
children: [
Expanded(
/*1*/
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/*2*/
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Text(
name,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
),
Text(
location,
style: TextStyle(
color: Colors.grey[500],
),
),
],
),
),
/*3*/
Icon(
Icons.star,
color: Colors.red[500],
),
const Text('41'),
],
),
);
}
}
1. To use all remaining free space in the row, use the Expanded widget to stretch the Column widget. To place the column at the
start of the row, set the crossAxisAlignment property to CrossAxisAlignment.start.
2. To add space between the rows of text, put those rows in a Padding widget.
https://docs.flutter.dev/ui/layout/tutorial 4/12
12/29/24, 1:21 PM Layout tutorial | Flutter
3. The title row ends with a red star icon and the text 41. The entire row falls inside a Padding widget and pads each edge by 32
pixels.
dart
- body: const Center(
- child: Text('Hello World'),
+ body: const SingleChildScrollView(
+ child: Column(
+ children: [
A SingleChildScrollView widget can scroll. This allows elements that don't fit on the current screen to display.
A Column widget displays any elements within its children property in the order listed. The first element listed in the
children list displays at the top of the list. Elements in the children list display in array order on the screen from top to
bottom.
dart
+ children: [
+ TitleSection(
+ name: 'Oeschinen Lake Campground',
+ location: 'Kandersteg, Switzerland',
+ ),
+ ],
lightbulb Tip
When pasting code into your app, indentation can become skewed. To fix this in your Flutter editor, use automatic
reformatting support.
To accelerate your development, try Flutter's hot reload feature.
If you have problems, compare your code to lib/main.dart.
The Button section contains three columns that use the same layout: an icon over a row of text.
Plan to distribute these columns in one row so each takes the same amount of space. Paint all text and icons with the primary
color.
https://docs.flutter.dev/ui/layout/tutorial 5/12
12/29/24, 1:21 PM Layout tutorial | Flutter
dart
class ButtonSection extends StatelessWidget {
const ButtonSection({super.key});
@override
Widget build(BuildContext context) {
final Color color = Theme.of(context).primaryColor;
// ···
}
}
https://docs.flutter.dev/ui/layout/tutorial 6/12
12/29/24, 1:21 PM Layout tutorial | Flutter
dart
class ButtonSection extends StatelessWidget {
const ButtonSection({super.key});
// ···
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, color: color),
Padding(
padding: const EdgeInsets.only(top: 8),
child: Text(
label,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w400,
color: color,
),
),
),
],
);
}
1. Add three instances of the ButtonWithText widget, once for each button.
2. Pass the color, Icon, and text for that specific button.
3. Align the columns along the main axis with the MainAxisAlignment.spaceEvenly value. The main axis for a Row widget is
horizontal and the main axis for a Column widget is vertical. This value, then, tells Flutter to arrange the free space in equal
amounts before, between, and after each column along the Row.
https://docs.flutter.dev/ui/layout/tutorial 7/12
12/29/24, 1:21 PM Layout tutorial | Flutter
dart
class ButtonSection extends StatelessWidget {
const ButtonSection({super.key});
@override
Widget build(BuildContext context) {
final Color color = Theme.of(context).primaryColor;
return SizedBox(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ButtonWithText(
color: color,
icon: Icons.call,
label: 'CALL',
),
ButtonWithText(
color: color,
icon: Icons.near_me,
label: 'ROUTE',
),
ButtonWithText(
color: color,
icon: Icons.share,
label: 'SHARE',
),
],
),
);
}
}
@override
Widget build(BuildContext context) {
return Column(
// ···
);
}
}
https://docs.flutter.dev/ui/layout/tutorial 8/12
12/29/24, 1:21 PM Layout tutorial | Flutter
dart
TitleSection(
name: 'Oeschinen Lake Campground',
location: 'Kandersteg, Switzerland',
),
+ ButtonSection(),
],
dart
class TextSection extends StatelessWidget {
const TextSection({
super.key,
required this.description,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(32),
child: Text(
description,
softWrap: true,
),
);
}
}
By setting softWrap to true, text lines fill the column width before wrapping at a word boundary.
https://docs.flutter.dev/ui/layout/tutorial 9/12
12/29/24, 1:21 PM Layout tutorial | Flutter
dart
location: 'Kandersteg, Switzerland',
),
ButtonSection(),
+ TextSection(
+ description:
+ 'Lake Oeschinen lies at the foot of the Blüemlisalp in the '
+ 'Bernese Alps. Situated 1,578 meters above sea level, it '
+ 'is one of the larger Alpine Lakes. A gondola ride from '
+ 'Kandersteg, followed by a half-hour walk through pastures '
+ 'and pine forest, leads you to the lake, which warms to 20 '
+ 'degrees Celsius in the summer. Activities enjoyed here '
+ 'include rowing, and riding the summer toboggan run.',
+ ),
],
2. Download the lake.jpg image and add it to the new images directory.
info Note
You can't use wget to save this binary file. You can download the image from Unsplash under the Unsplash License.
The small size comes in at 94.4 kB.
3. To include images, add an assets tag to the pubspec.yaml file at the root directory of your app. When you add assets, it
serves as the set of pointers to the images available to your code.
pubspec.yaml
yaml
flutter:
uses-material-design: true
+ assets:
+ - images/lake.jpg
lightbulb Tip
Text in the pubspec.yaml respects whitespace and text case. Write the changes to the file as given in the previous example.
This change might require you to restart the running program to display the image.
https://docs.flutter.dev/ui/layout/tutorial 10/12
12/29/24, 1:21 PM Layout tutorial | Flutter
dart
class ImageSection extends StatelessWidget {
const ImageSection({super.key, required this.image});
@override
Widget build(BuildContext context) {
return Image.asset(
image,
width: 600,
height: 240,
fit: BoxFit.cover,
);
}
}
The BoxFit.cover value tells Flutter to display the image with two constraints. First, display the image as small as possible.
Second, cover all the space that the layout allotted, called the render box.
dart
children: [
+ ImageSection(
+ image: 'images/lake.jpg',
+ ),
TitleSection(
name: 'Oeschinen Lake Campground',
location: 'Kandersteg, Switzerland',
Congratulations
That's it! When you hot reload the app, your app should look like this.
Resources
You can access the resources used in this tutorial from these locations:
https://docs.flutter.dev/ui/layout/tutorial 11/12
12/29/24, 1:21 PM Layout tutorial | Flutter
Next Steps
To add interactivity to this layout, follow the interactivity tutorial.
https://docs.flutter.dev/ui/layout/tutorial 12/12