Flutter Tutorial 2
Flutter Tutorial 2
Docs
Development
UI
Layout
Tutorial
What you’ll learn
How Flutter’s layout mechanism works.
How to lay out widgets vertically and horizontally.
How to build a Flutter layout.
This is a guide to building layouts in Flutter. You’ll build the layout for the
following app:
If you want a “big picture” understanding of the layout mechanism, start with
Flutter’s approach to layout.
{codelabs/startup_namer/step1_base → layout/base}/lib/main.dart
@@ -10,10 +10,10 @@
1010 @override
1111 Widget build(BuildContext context) {
1212 return MaterialApp(
13 - title: 'Welcome to Flutter',
13 + title: 'Flutter layout demo',
1414 home: Scaffold(
1515 appBar: AppBar(
16 - title: Text('Welcome to Flutter'),
16 + title: Text('Flutter layout demo'),
1717 ),
1818 body: Center(
1919 child: Text('Hello World'),
Step 1: Diagram the layout
The first step is to break the layout down to its basic elements:
Title section
The second row, called the Button section, also has 3 children: each child is a
column that contains an icon and text.
Button section
Once the layout has been diagrammed, it’s easiest to take a bottom-up approach to
implementing it. To minimize the visual confusion of deeply nested layout code,
place some of the implementation in variables and functions.
lib/main.dart (titleSection)
content_copy
Widget titleSection = Container(
padding: const EdgeInsets.all(32),
child: Row(
children: [
Expanded(
/*1*/
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/*2*/
Container(
padding: const EdgeInsets.only(bottom: 8),
child: Text(
'Oeschinen Lake Campground',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
Text(
'Kandersteg, Switzerland',
style: TextStyle(
color: Colors.grey[500],
),
),
],
),
),
/*3*/
Icon(
Icons.star,
color: Colors.red[500],
),
Text('41'),
],
),
);
Putting a Column inside an Expanded widget stretches the column to use all
remaining free space in the row. Setting the crossAxisAlignment property to
CrossAxisAlignment.start positions the column at the start of the row.
Putting the first row of text inside a Container enables you to add padding. The
second child in the Column, also text, displays as grey.
The last two items in the title row are a star icon, painted red, and the text
“41”. The entire row is in a Container and padded along each edge by 32 pixels.
Add the title section to the app body like this:
{../base → step2}/lib/main.dart
@@ -12,11 +46,13 @@
1246 return MaterialApp(
1347 title: 'Flutter layout demo',
1448 home: Scaffold(
1549 appBar: AppBar(
1650 title: Text('Flutter layout demo'),
1751 ),
18 - body: Center(
19 - child: Text('Hello World'),
52 + body: Column(
53 + children: [
54 + titleSection,
55 + ],
2056 ),
2157 ),
2258 );
Tip:
When pasting code into your app, indentation can become skewed. You can fix this in
your Flutter editor using the automatic reformatting support.
For a faster development experience, try Flutter’s hot reload feature.
If you have problems, compare your code to lib/main.dart.
Step 3: Implement the button row
The button section contains 3 columns that use the same layout—an icon over a row
of text. The columns in this row are evenly spaced, and the text and icons are
painted with the primary color.
Since the code for building each column is almost identical, create a private
helper method named buildButtonColumn(), which takes a color, an Icon and Text, and
returns a column with its widgets painted in the given color.
lib/main.dart (_buildButtonColumn)
content_copy
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// ···
}
Build the row containing these columns by calling the function and passing the
color, Icon, and text specific to that column. Align the columns along the main
axis using MainAxisAlignment.spaceEvenly to arrange the free space evenly before,
between, and after each column. Add the following code just below the titleSection
declaration inside the build() method:
lib/main.dart (buttonSection)
content_copy
Color color = Theme.of(context).primaryColor;
{step2 → step3}/lib/main.dart
@@ -46,3 +59,3 @@
4659 return MaterialApp(
4760 title: 'Flutter layout demo',
4861 home: Scaffold(
@@ -52,8 +65,9 @@
5265 body: Column(
5366 children: [
5467 titleSection,
68 + buttonSection,
5569 ],
5670 ),
5771 ),
5872 );
5973 }
Step 4: Implement the text section
Define the text section as a variable. Put the text in a Container and add padding
along each edge. Add the following code just below the buttonSection declaration:
lib/main.dart (textSection)
content_copy
Widget textSection = Container(
padding: const EdgeInsets.all(32),
child: Text(
'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.',
softWrap: true,
),
);
By setting softwrap to true, text lines will fill the column width before wrapping
at a word boundary.
{step3 → step4}/lib/main.dart
@@ -59,3 +72,3 @@
5972 return MaterialApp(
6073 title: 'Flutter layout demo',
6174 home: Scaffold(
@@ -66,6 +79,7 @@
6679 children: [
6780 titleSection,
6881 buttonSection,
82 + textSection,
6983 ],
7084 ),
7185 ),
Step 5: Implement the image section
Three of the four column elements are now complete, leaving only the image. Add the
image file to the example:
Note that wget doesn’t work for saving this binary file. The original image is
available online under a Creative Commons license, but it’s large and slow to
fetch.
Update the pubspec.yaml file to include an assets tag. This makes the image
available to your code.
{step4 → step5}/pubspec.yaml
@@ -17,3 +17,5 @@
1717 flutter:
1818 uses-material-design: true
19 + assets:
20 + - images/lake.jpg
Tip:
Note that pubspec.yaml is case sensitive. So, you should write assets: and image
address as above shown format.
For image address proper indentation must be there.
Now you can reference the image from your code:
{step4 → step5}/lib/main.dart
@@ -77,6 +77,12 @@
7777 ),
7878 body: Column(
7979 children: [
80 + Image.asset(
81 + 'images/lake.jpg',
82 + width: 600,
83 + height: 240,
84 + fit: BoxFit.cover,
85 + ),
8086 titleSection,
8187 buttonSection,
8288 textSection,
BoxFit.cover tells the framework that the image should be as small as possible but
cover its entire render box.
{step5 → step6}/lib/main.dart
@@ -72,13 +77,13 @@
7277 return MaterialApp(
7378 title: 'Flutter layout demo',
7479 home: Scaffold(
7580 appBar: AppBar(
7681 title: Text('Flutter layout demo'),
7782 ),
78 - body: Column(
83 + body: ListView(
7984 children: [
8085 Image.asset(
8186 'images/lake.jpg',
8287 width: 600,
8388 height: 240,
8489 fit: BoxFit.cover,
Dart code: main.dart
Image: images
Pubspec: pubspec.yaml
That’s it! When you hot reload the app, you should see the same app layout as the
screenshot at the top of this page.
You can add interactivity to this layout by following Adding Interactivity to Your
Flutter App.