Layout Basics

Summary

we'll take a first look at the mockups we want to implement for this course for our "Tourism & Co." app. We'll start to implement the "detail screen" of the app, where an image is shown at the top along with some text below. We'll cover some Flutter layout concepts to ensure our page's content is laid out properly.

In this lesson we'll cover: working with layout using Column, mainAxisAlignment and crossAxisAlignment

Note: you can check out the video for this post here.

The Code for This Lesson

Check out the tourismandco repo's step/step02 branch for the code we'll cover in this lesson.

What We're Working Toward

We'll be implementing three text sections which will be part of our "Location Detail" screen for the Tourism & Co. app. Later, these text sections will be dynamic but for now, we'll just create three so that text sections of our screen has its own widget.

tourismandco-screenshot1

Basic Layout Concepts in Flutter

Layout controls the way content in your is constraied or expands in a given area. Your app can be shown on various screen sizes, can be rotated and content can change dynamically. Content can be images, text, buttons or really anything. It's important to ensure this content is nicely contained to the user.

The most common layout pattern, especially for mobile phones in particular, is a "Column" of content, where each item in the column flows from top to bottom. For this type of layout, Flutter defines something called the "main axis", which for a Column is a vertical line going through the widget. For other widgets, such as the Row widget, this "main axis" also exists, but is instead a horizontal row going from left to right of the widget.

We also have the converse of "main axis" which is the "cross axis". In other words, this is the "other" axis of a given layout widget. So for Column, the "cross axis" is a horizontal line going through each child of Column. For Row, it'd instead be a vertical line going through each child.

Layout using Column, mainAxisAlignment and crossAxisAlignment

Using the Column Widget

// location_detail/location_detail.dart

// WARNING: not the final implementation of this lesson

import 'package:flutter/material.dart';
import 'text_section.dart';

class LocationDetail extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Hello'),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Container(
              decoration: BoxDecoration(
                color: Colors.red,
              ),
              child: Text('hi'),
            ),
              Container(
              decoration: BoxDecoration(
                color: Colors.green,
              ),
              child: Text('hi'),
            ),
              Container(
              decoration: BoxDecoration(
                color: Colors.blue,
              ),
              child: Text('hi'),
            ),
          ],
        ));
  }
}

Here we define a few text sections, using the Column widget. We're showing a block of color using the Container widget, where each block is a different color. This will help us see the different layout options we have available to us by changing mainAxisAlignment and crossAxisAlignment.

Notice what happens when you use:

Implementing our own Parameterized Widget, TextSection

After playing around with our Column widget, let's clean up our code. We'll implement our own new StatelessWidget so we can re-use our code.

// location_detail/text_section.dart

import 'package:flutter/material.dart';

class TextSection extends StatelessWidget {
  final Color _color;

  TextSection(this._color);

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        color: _color,
      ),
      child: Text('hi'),
    );
  }
}

Finally, let's update our location_detail/location_detail.dart file to use our new widget:

// location_detail/location_detail.dart

import 'package:flutter/material.dart';
import 'text_section.dart';

class LocationDetail extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Hello'),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            TextSection(Colors.red),
            TextSection(Colors.green),
            TextSection(Colors.blue),
          ],
        ));
  }
}

Lastly, let's update our app.dart file to:

// app.dart

import 'package:flutter/material.dart';
import 'screens/location_detail/location_detail.dart';

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: LocationDetail(),
    );
  }
}

Summary

We can now implement the real content of our screen, now that our layout is defined.