o7planning

Flutter Column Tutorial

View more Tutorials:

1- Flutter Column

Column is a widget that displays its child widgets on a column. Another variation is Row which shows its child widgets on a row.
To make a child widget of Column expand to fill the available vertical space, you can wrap it in an Expanded object.
Column places its children on one column and cannot be scrolled. If you want a similar and scrollable container, you should consider using ListView.
Column Constructor:
Column Constructor
Column(
    {Key key,
    List<Widget> children: const <Widget>[],
    MainAxisAlignment mainAxisAlignment: MainAxisAlignment.start,
    MainAxisSize mainAxisSize: MainAxisSize.max,
    CrossAxisAlignment crossAxisAlignment: CrossAxisAlignment.center,
    TextDirection textDirection,
    VerticalDirection verticalDirection: VerticalDirection.down,
    TextBaseline textBaseline
    }
)

2- children

children property is used to define a list of child widgets of Column.
You can add child widgets to children, or remove widgets from children, but you have to follow the rule that is mentioned in the "Add/Remove Children" section.
List<Widget> children: const <Widget>[]
Let's get started with our first example, a Column with four child widgets:
main.dart (children ex1)
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'o7planning.org',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text("Flutter Column Example")
      ),
      body: Center(
          child: Column (
              children: [
                ElevatedButton(child: Text("Button 1"), onPressed:(){}),
                Icon(Icons.ac_unit, size: 48, color: Colors.blue),
                ElevatedButton(
                    child: Text("Button 2"),
                    onPressed:(){},
                    style: ButtonStyle(
                        minimumSize: MaterialStateProperty.all(Size.square(70))
                    )
                ),
                ElevatedButton(child: Text("Very Long Button 3"), onPressed:(){}),
              ]
          )
      ),
    );
  }
}
Some child widgets with flex > 0 is able to expand its height to fill the remaining space vertically such as Expanded, Spacer, etc. They are often used to adjust the distance among the child widgets of Column. Here is an example:
children (ex2)
Column (
  children: [
    ElevatedButton(child: Text("Button 1"), onPressed:(){}),
    Expanded (
        flex: 2,
        child: Icon(Icons.ac_unit, size: 48, color: Colors.blue)
    ),
    ElevatedButton(
        child: Text("Button 2"),
        onPressed:(){},
        style: ButtonStyle(
            minimumSize: MaterialStateProperty.all(Size.square(70))
        )
    ),
    Spacer(flex: 1),
    ElevatedButton(child: Text("Very Long Button 3"), onPressed:(){}),
  ]
)

3- Add/Remove children

You can add a few child widgets to a Column or remove some of them from Column. Doing what is shown below may lead to unexpected results:
** Not Working! **
class SomeWidgetState extends State<SomeWidget> {
  List<Widget> _children;

  void initState() {
    _children = [];
  }

  void someHandler() {
    setState(() {
        _children.add(newWidget);
    });
  }

  Widget build(BuildContext context) {
    // Reusing `List<Widget> _children` here is problematic.
    return Column(children: this._children);
  }
}
To solve the above problem, you need to comply with the following rules:
  1. Child widgets need to be explicitly assigned a Key value, which helps Flutter recognize old or new child widgets as the number of child widgets changes.
  2. A new List object need to be created for Column.children if a certain child widget changes, or the number of child widgets does.
** Worked! **
class SomeWidgetState extends State<SomeWidget> {
  List<Widget> _children;

  void initState() {
    this._children = [];
  }

  // Add or remove some children..
  void someHandler() {
    setState(() {
      // The key here allows Flutter to reuse the underlying render
      // objects even if the children list is recreated.
      this._children.add(newWidget(key: ...));
    });
  }

  Widget build(BuildContext context) {
    // Always create a new list of children as a Widget is immutable.
    var newChildren = List.from(this._children);
    this._children = newChildren;
    
    return Column(children: this._children);
  }
}
For example:
main.dart (children ex3)
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'o7planning.org',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    return MyHomePageState();
  }
}


class MyHomePageState extends State<MyHomePage> {
  List<Widget> _children = [];
  int idx = 0;

  @override
  void initState()  {
    super.initState();

    this._children = [
      ElevatedButton(
          key: Key(this.idx.toString()),
          child: Text("Button " + idx.toString()),
          onPressed: (){}
      )
    ];
  }

  void addChildHandler()  {
    this.idx++;
    this.setState(() {
      var newChild = ElevatedButton(
          key: Key(this.idx.toString()),
          child: Text("Button " + idx.toString()),
          onPressed: (){}
      );
      this._children.add(newChild);
    });
  }

  @override
  Widget build(BuildContext context) {
    // Create new List object:

    this._children = this._children == null? [] : List.from(this._children);

    return Scaffold(
      appBar: AppBar(
          title: Text("Flutter Column Example")
      ),
      body: Center(
          child: Column (
              children:  this._children
          )
      ),
      floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add),
          onPressed: ()  {
            this.addChildHandler();
          }
      ),
    );
  }
}

4- mainAxisAlignment

mainAxisAlignment property is used to specify how the child widgets will be arranged on the main axis. As for Column, the main axis is the main vertical axis.
MainAxisAlignment mainAxisAlignment: MainAxisAlignment.start

MainAxisAlignment.start

In case verticalDirection = VerticalDirection.down (Default) and mainAxisAlignment = MainAxisAlignment.start, the child widgets of Column will be placed side by side from top to bottom.
MainAxisAlignment.start
Column (
    mainAxisAlignment: MainAxisAlignment.start,
    children: [
      ElevatedButton(child: Text("Long Button 1"), onPressed:(){}),
      ElevatedButton(
          child: Text("Button 2"),
          onPressed:(){},
          style: ButtonStyle(
              minimumSize: MaterialStateProperty.all(Size.square(70))
          )
      ),
      ElevatedButton(child: Text("Very Long Button 3"), onPressed:(){})
    ]
)

MainAxisAlignment.center

mainAxisAlignment: MainAxisAlignment.center

MainAxisAlignment.end

With  verticalDirection = VerticalDirection.down (Default) and mainAxisAlignment = MainAxisAlignment.end, the child widgets of Column will be placed side by side from bottom to top.
mainAxisAlignment: MainAxisAlignment.end

MainAxisAlignment.spaceBetween

mainAxisAlignment: MainAxisAlignment.spaceBetween

MainAxisAlignment.spaceEvenly

mainAxisAlignment: MainAxisAlignment.spaceEvenly

MainAxisAlignment.spaceAround

mainAxisAlignment: MainAxisAlignment.spaceAround

5- mainAxisSize

mainAxisSize property specifies how much vertical space should be occupied by Column. Its default value is MainAxisSize.max meaning Column tries to occupy as much vertical space as possible.
If there is a child widget with "flex > 0 && fit != FlexFit.loose"Column ​​​​​​​will try to take up as much space as possible regardless of the value of mainAxisSize.
Conversely, if mainAxisSize = MainAxisSize.min, Column will have a sufficient height for all of its child widgets.
MainAxisSize mainAxisSize: MainAxisSize.max

6- crossAxisAlignment

crossAxisAlignment property is used to specify how the child widgets will be arranged on the cross axis. As for Column, the cross axis is the horizontal axis.
CrossAxisAlignment crossAxisAlignment: CrossAxisAlignment.center

CrossAxisAlignment.start

In case textDirection = TextDirection.ltr (Default) and crossAxisAlignment = CrossAxisAlignment.start, the child widgets of Column will be placed close to its left edge.

CrossAxisAlignment.center  (Default).

crossAxisAlignment: CrossAxisAlignment.center

CrossAxisAlignment.end

In case textDirection = TextDirection.ltr (Default) and crossAxisAlignment = CrossAxisAlignment.end, the child widgets of Column will be placed close to the right edge of the Column.
crossAxisAlignment: CrossAxisAlignment.end

CrossAxisAlignment.stretch

crossAxisAlignment: CrossAxisAlignment.stretch

CrossAxisAlignment.baseline

crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic
 

7- textDirection

textDirection property specifies how the child widgets of Column will be arranged on the horizontal axis and how the words "start" and "end" are interpreted.
TextDirection textDirection

// TextDirection enum:

TextDirection.ltr (Left to Right) (Default)
TextDirection.rtl (Right to Left)
If textDirection = TextDirection.ltr (Default), the word "start" will correspond to "left" and the word "end" will correspond to "right".
In contrast, in case textDirection = TextDirection.rtl, the word "start" will correspond to "right" and the word "end" will correspond to "left".

8- verticalDirection

verticalDirection property specifies how the child widgets of Column will be arranged on the main axis (vertical axis) and how the words "start" and "end" are interpreted.
VerticalDirection verticalDirection: VerticalDirection.down

// VerticalDirection enum:

VerticalDirection.down (Default)
VerticalDirection.up
If verticalDirection = VerticalDirection.down (Default), the word "start" will correspond to "top" and the word "end" will correspond to "bottom".
Conversely, if verticalDirection = VerticalDirection.up, the word "start" will correspond to "bottom" and the word "end" will correspond to "top".

9- textBaseline

If aligning the child widgets based on the baseline, the textBaseline property specifies what kind of baseline will be used.
TextBaseline textBaseline: TextBaseline.alphabetic

// TextBaseline enum:

TextBaseline.alphabetic  (Default)
TextBaseline.ideographic
For example:
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic

View more Tutorials:

Maybe you are interested

These are online courses outside the o7planning website that we introduced, which may include free or discounted courses.