Space between Column's children in Flutter
Asked Answered
J

29

276

I have a Column widget with two TextField widgets as children and I want to have some space between both of them.

I already tried mainAxisAlignment: MainAxisAlignment.spaceAround, but the result was not what I wanted.

Jaymejaymee answered 12/10, 2018 at 8:0 Comment(2)
Simply Put SizedBox( height: 15.0, ), Between the two TextFieldAppointment
margin: EdgeInsets.only(left: 200.0, top: 300.0))Expose
S
339

You can use Padding widget in between those two widget or wrap those widgets with Padding widget.

Update

SizedBox widget can be use in between two widget to add space between two widget and it makes code more readable than padding widget.

Ex:

Column(
  children: <Widget>[
    Widget1(),
    SizedBox(height: 10),
    Widget2(),
  ],
),
Stewartstewed answered 12/10, 2018 at 8:4 Comment(6)
I sure wish that column-class had that property included. It will be a waste of coding time for getting a padding between all children.Larder
How can you wrap two widget in a Padding widget when padding widgets only take a single child parameter?Approximal
@ScottF the answer said that the Padding widget goes in between the 2 widgets. It's not that the 2 widgets becomes children of Padding.Telly
It straight up says "or wrap those widgets with Padding widget"....Approximal
@ScottF Make the child a column or row with the two widgets as children.Safety
You can have similar result just replacing what our colleague Viren did by: Padding(padding: EdgeInsets.all(yourDesiredPaddingValue)).Personality
P
177

You can put a SizedBox with a specific height between the widgets, like so:

Column(
  children: <Widget>[
    FirstWidget(),
    SizedBox(height: 100),
    SecondWidget(),
  ],
),

Why to prefer this over wrapping the widgets in Padding? Readability! There is less visual boilerplate, less indention and the code follows the typical reading-order.

Papist answered 14/10, 2018 at 7:10 Comment(2)
Adding a sized box is like adding an empty view right ? would nt that lead to any problems ?Pendergast
SizedBox is just a normal widget that has a desired size it tries to be during layout, but doesn't render anything. All the leaf widgets like Text or Container are empty too, so that's okay.Papist
T
159

There are many ways of doing it, I'm listing a few here.

  1. Use SizedBox and provide some height:

     Column(
       children: <Widget>[
         Widget1(),
         SizedBox(height: 10), // <-- Set height
         Widget2(),
       ],
     )
    
  2. Use Spacer

     Column(
       children: <Widget>[
         Widget1(),
         Spacer(), // <-- Spacer
         Widget2(),
       ],
     )
    
  3. Use Expanded

     Column(
       children: <Widget>[
         Widget1(),
         Expanded(child: SizedBox.shrink()), // <-- Expanded
         Widget2(),
       ],
     )
    
  4. Set mainAxisAlignment

     Column(
       mainAxisAlignment: MainAxisAlignment.spaceAround, // <-- alignments
       children: <Widget>[
         Widget1(),
         Widget2(),
       ],
     )
    
  5. Use Wrap

     Wrap(
       direction: Axis.vertical, 
       spacing: 20, // <-- Spacing between children
       children: <Widget>[
         Widget1(),
         Widget2(),
       ],
     )
    
Trigonometry answered 12/10, 2019 at 19:1 Comment(3)
This is SUPER helpful to know all the different ways to do. Thanks for sharing!Zachery
Another one is to wrap Widget2 inside a Padding with padding: EdgeInsets.only(top: 20).Xavier
I agree this answer is the most helpful. Especially the Wrap showing direction in vertical axis. Thanks!Edaedacious
C
154

you can use Wrap() widget instead Column() to add space between child widgets.And use spacing property to give equal spacing between children

Wrap(
  spacing: 20, // to apply margin in the main axis of the wrap
  runSpacing: 20, // to apply margin in the cross axis of the wrap
  children: <Widget>[
     Text('child 1'),
     Text('child 2')
  ]
)
Conventionalize answered 12/5, 2019 at 7:50 Comment(8)
Use runSpacing instead of spacing for gaps in between vertically spaced itemsHeliometer
This worked to me. I think it is the best solution at all but what would be the disavantages of using Wrap() instead of Column() ?Delvalle
Column is an expanded widget while Wrap isn't. so when you want to expand the whole space of the parent, you should use expanded widgets like Column or Row, etc. This depends on your caseConventionalize
Yes, this is much better than wrapping each child individually. Good suggestion.Zerla
which is better for Flutter Web?Pettis
This is perfect if you want to bring two widgets closer together. Just make the runSpacing a negative value.Hizar
This doesn't put it in a column layout, does it?Kenneth
even direction: Axis.horizontal doesn't make it look like a columnKenneth
T
38

Just use padding to wrap it like this:

Column(
  children: <Widget>[
  Padding(
    padding: EdgeInsets.all(8.0),
    child: Text('Hello World!'),
  ),
  Padding(
    padding: EdgeInsets.all(8.0),
    child: Text('Hello World2!'),
  )
]);

You can also use Container(padding...) or SizeBox(height: x.x). The last one is the most common but it will depents of how you want to manage the space of your widgets, I like to use padding if the space is part of the widget indeed and use sizebox for lists for example.

Tipper answered 12/10, 2018 at 21:40 Comment(1)
is there a way to do something like css grid-gap?Snowonthemountain
A
26

I don't see this solution here, so just for the sake of completeness I'll post it.

You can also wrap children with Padding using map:

Column(
      children: [Text('child 1'), Text('child 2')]
          .map(
            (e) => Padding(
              padding: const EdgeInsets.all(8),
              child: e,
            ),
          )
          .toList(),
    );
Asgard answered 18/3, 2021 at 14:31 Comment(2)
This is a better way than adding sizedBox() after each widget.Ledge
@Ledge it's useful sometimes, yet it doesn't really add the space between items, but around them.Ushijima
B
17

I also wish there was some built-in way in Flutter to do this. Like a parameter you could pass to Column or Row. Sometimes you don't want padding around every element but you want space between them. Especially if you have more than two children, it's kind of tedious to write something like

const double gap = 10;
return Column(
  children: [
    Text('Child 1'),
    SizedBox(height: gap),
    Text('Child 2'),
    SizedBox(height: gap),
    Text('Child 3'),
    SizedBox(height: gap),
    Text('Child 4'),
  ],
);

However, I've came up with one quick (not perfect) solution:

Add this somewhere in your project (only once):

extension ListSpaceBetweenExtension on List<Widget> {
  List<Widget> withSpaceBetween({double? width, double? height}) => [
    for (int i = 0; i < length; i++)
      ...[
        if (i > 0)
          SizedBox(width: width, height: height),
        this[i],
      ],
  ];
}

And from now on whenever you have a Row or a Column, you can write

Column(
  children: [
    Text('Child 1'),
    Text('Child 2'),
    Text('Child 3'),
    Text('Child 4'),
  ].withSpaceBetween(height: 10),
),

When using Row you'll have to replace 'height' with 'width'.

Boff answered 4/2, 2022 at 23:8 Comment(3)
This is the best answer in my opinion. Clear to read, concise, and doesn't leave leading or trailing spaces like the map based solutions.Gidgetgie
I like this answer, but you can improve performance for larger lists by using adding the first element and then iterating from index 1 (instead of zero) [if (isNotEmpty) this[0], for (int i = 1; i < length; i++) ...[SizedBox(width: width, height: height), this[i]]]. This way element 0 is added and all remaining elements do not require an if check.Caricaria
This extension is brilliant and should become the accepted answer. It is particularly valuable when you just want to pass a list of widgets to your column in the first place, because you don't have the option to add the SizedBoxes manually in that case even if you wanted to.Etude
M
9
Column(
  children: <Widget>[
    FirstWidget(),
    Spacer(),
    SecondWidget(),
  ]
)

Spacer creates a flexible space to insert into a [Flexible] widget. (Like a column)

Mezereon answered 31/7, 2019 at 19:2 Comment(1)
Please add some explanation to your answer to help others understand it better. Code only answers are considered impolite and it may not help the OP understand the problem that you are trying to help with.Featherston
C
7

The same way SizedBox is used above for the purpose of code readability, you can use the Padding widget in the same manner and not have to make it a parent widget to any of the Column's children

Column(
  children: <Widget>[
    FirstWidget(),
    Padding(padding: EdgeInsets.only(top: 40.0)),
    SecondWidget(),
  ]
)
Crow answered 1/6, 2019 at 21:35 Comment(0)
G
6

If you don't wanna wrap Padding with every widget or repeat SizedBox.

Try this:

Column(
        children: [
          Widget(),
          Widget(),
          Widget(),
          Widget(),
        ]
            .map((e) => Padding(
                  child: e,
                  padding: const EdgeInsets.symmetric(vertical: 10),
                ))
            .toList(),
      ),

That will warp all the widgets with padding without repetition.

Govern answered 17/9, 2021 at 13:15 Comment(2)
The answer needs supporting information for better understanding.Pavlish
@Pavlish I've added more detailsGovern
A
4

Columns Has no height by default, You can Wrap your Column to the Container and add the specific height to your Container. Then You can use something like below:

Container(
   width: double.infinity,//Your desire Width
   height: height,//Your desire Height
   child: Column(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: <Widget>[
         Text('One'),
         Text('Two')
      ],
   ),
),
Aphra answered 2/6, 2020 at 8:56 Comment(0)
B
3

You can solve this problem in different way.

If you use Row/Column then you have to use mainAxisAlignment: MainAxisAlignment.spaceEvenly

If you use Wrap Widget you have to use runSpacing: 5, spacing: 10,

In anywhere you can use SizeBox()

Breban answered 28/8, 2019 at 6:25 Comment(0)
H
3

Inspired by https://mcmap.net/q/108105/-space-between-column-39-s-children-in-flutter, use extension on List<Widget> to add the SizedBox:

extension on List<Widget> {
  List<Widget> insertBetweenAll(Widget widget) {
    var result = List<Widget>.empty(growable: true);
    for (int i = 0; i < length; i++) {
      result.add(this[i]);
      if (i != length - 1) {
        result.add(widget);
      }
    }
    return result;
  }
}

Use like this:

Column(children: [
  Widget1(),
  Widget2(),
  Widget3(),
].insertBetweenAll(SizedBox(height: 20)))
Hsining answered 26/10, 2022 at 13:6 Comment(0)
A
2

You can also use a helper function to add spacing after each child.

List<Widget> childrenWithSpacing({
  @required List<Widget> children,
  double spacing = 8,
}) {
  final space = Container(width: spacing, height: spacing);
  return children.expand((widget) => [widget, space]).toList();
}

So then, the returned list may be used as a children of a column

Column(
  children: childrenWithSpacing(
    spacing: 14,
    children: [
      Text('This becomes a text with an adjacent spacing'),
      if (true == true) Text('Also, makes it easy to add conditional widgets'),
    ],
  ),
);

I'm not sure though if it's wrong or have a performance penalty to run the children through a helper function for the same goal?

Adlei answered 4/12, 2020 at 11:2 Comment(1)
What if I want to remove space between any two children widgets?Grefe
B
2

Column widget doesn't have its own height, it just expanded as we added inside the children widget. for if you need the same space between multiple widgets so,

Container(
   width: double.infinity,
   height: height,
   child: Column(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: <Widget>[
         Text('One'),
         Text('Two'),
         Text('Three'),
         Text('Four')
      ],
   ),
),

or just added custom space between them by using SizeBox, Spacer, or widget, like this

Column(
   children: <Widget>[
         Text('One'),
         SizedBox(height: 20), 
         Text('Two'),
         SizedBox(height: 40), 
         Text('Three'),
         SizedBox(height: 30), 
         Text('Four')
   ],
 ),
Brose answered 18/2, 2022 at 13:36 Comment(0)
R
2

Flutter extension can be beneficial here, and if we've too many children and want to add some padding between children, we can create an extension on Column. Here is an example

extension ColumnExtension on Column {
  Column childrenPadding(EdgeInsets padding) {
    return Column(
      children: children.map((e) => e.padding(padding)).toList(),
    );
  }
}

Usage

class SettingsPage extends StatelessWidget {
  const SettingsPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(AppStrings.settings)),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            SettingTile(
              title: AppStrings.darkMode,
              leading: Icon(LineIcons.sun, color: context.primary),
            ),
            SettingTile(
              title: AppStrings.language,
              leading: Icon(LineIcons.language, color: context.primary),
            ),
            SettingTile(
              title: AppStrings.language,
              leading: Icon(LineIcons.language, color: context.primary),
            ),
            SettingTile(
              title: AppStrings.language,
              leading: Icon(LineIcons.language, color: context.primary),
            ),
          ],
        ).childrenPadding(const EdgeInsets.only(bottom: 8.0)),
      ),
    );
  }
}

Result

Column Extension example

Ravo answered 10/12, 2023 at 10:34 Comment(0)
O
1
Column(children: <Widget>[
   Container(margin: EdgeInsets.only(top:12, child: yourWidget)),
   Container(margin: EdgeInsets.only(top:12, child: yourWidget))
]);
Olaolaf answered 21/11, 2019 at 5:22 Comment(0)
S
1

Adding multiple sized boxes gets tedious if you have too many children in a column, row, listView, etc., and if you have to do the same thing in many places in your application.

You can use the following utils to encapsulate the logic of adding these sized boxes:

List<Widget> addHorizontalSpaceBetweenElements(double space, List<Widget> widgets) {
  return _addSpaceBetweenElements(widgets, () => SizedBox(width: space));
}

List<Widget> addVerticalSpaceBetweenElements(double space, List<Widget> widgets) {
  return _addSpaceBetweenElements(widgets, () => SizedBox(height: space));
}

List<Widget> _addSpaceBetweenElements(List<Widget> widgets, ValueGetter<SizedBox> sizedBoxGetter) {
  if (widgets.isEmpty || widgets.length == 1) {
    return widgets;
  }
  List<Widget> spacedWidgets = [widgets.first];
  for (var i = 1; i < widgets.length - 1; i++) {
    spacedWidgets.add(sizedBoxGetter());
    spacedWidgets.add(widgets[i]);
  }
  spacedWidgets.add(sizedBoxGetter());
  spacedWidgets.add(widgets.last);
  return spacedWidgets;
}


And you use them like this:

Column(
  children: addVerticalSpaceBetweenElements(5, [
    Text(),
    Text(),
  Row(children: addHorizontalSpaceBetweenElements(5, [
    Text(),
    Text(),
  ])),
  ]));
Subshrub answered 9/11, 2022 at 7:15 Comment(0)
M
1
**// provide fixed space defined in sizedbox**


 Column(
     children: [
          widget1(),
          sizedbox(height:20), 
          widget2()
        ] 
     )

**// Provides equal space between childs** 

Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
     widget1(),
     widget2()
   ] 
)
Meakem answered 2/3, 2023 at 3:25 Comment(0)
B
1

Another alternative I'm surprised isn't listed here is to simply use ListView.separated. I use this quite a lot for lists, often using const Divider() as a material-style separator line for the spacer.

List<Widget> yourListOfWidgets = [
  const Text("Foo"),
  const Text("Bar"),
];
    
return ListView.separated(
  itemCount: yourListOfWidgets.length,
  itemBuilder: (context, index) => yourListOfWidgets[index],
  separatorBuilder: (context, index) => const SizedBox(height: 10),
)
Brecher answered 8/3, 2023 at 17:27 Comment(0)
M
1

Basically all of the above answers are totally fine for small pieces of UI but if you are looking for a reusable and clean way to place a separator widget inside of a column, this might be what you are looking for:

class SeparatedColumn extends Column {
  SeparatedColumn({
    Key? key,
    MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
    MainAxisSize mainAxisSize = MainAxisSize.max,
    CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
    TextDirection? textDirection,
    VerticalDirection verticalDirection = VerticalDirection.down,
    TextBaseline? textBaseline,
    Widget? separator,
    required List<Widget> children,
  }) : super(
          key: key,
          children: List.generate(
            children.length * 2 - 1,
            (index) => index % 2 == 0
                ? children[index ~/ 2]
                : separator ?? const SizedBox.shrink(),
          ),
          mainAxisAlignment: mainAxisAlignment,
          mainAxisSize: mainAxisSize,
          crossAxisAlignment: crossAxisAlignment,
          textDirection: textDirection,
          verticalDirection: verticalDirection,
          textBaseline: textBaseline,
        );
}
Mayflower answered 14/7, 2023 at 19:49 Comment(0)
H
0

You may have to use SizedBox() widget between your column's children. Hope that'll be usefull

Helenahelene answered 14/6, 2020 at 13:0 Comment(0)
C
0

Extract the input field widgets into a custom widget that is wrapped in padding or a container with padding (assuming symmetrical spacing).

Having sized boxes in-between every column child (as suggested in other answers) is not practical or maintainable. If you wanted to change the spacing you would have to change each sized box widget.

// An input field widget as an example column child
class MyCustomInputWidget extends StatelessWidget {
  const MyCustomInputWidget({Key? key})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    // wrapping text field in container
    return Container(
      // here is the padding :)
      padding: EdgeInsets.symmetric(vertical: 10),
      child: TextField(...)
    );
  }
}

...then the column in the parent class

column(
  children: <Widget>[
    MyCustomInputWidget(),
    SizedBox(height: 10),
    MyCustomInputWidget(),
  ],
),

Obviously you would want the custom widget to have some sort of constructor to handle different field parameters.

Compiler answered 1/9, 2022 at 19:41 Comment(0)
U
0

A package called spaces2 can be used for this purpose.

By the way below, you can easily implement spaces between objects in columns or rows.

// Without Gap
Column(children: [x,y,z]);
// With Gaps Added
SpacedColumn(spaceBetween: 10, children: [x,y,z]);
Unscathed answered 16/2 at 14:39 Comment(0)
S
-1

The sized box will not help in the case, the phone is in landscape mode.

body: Column(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: <Widget>[
        Expanded(
           child: Container(
            margin: EdgeInsets.all(15.0),
            decoration: BoxDecoration(
              color: Color(0xFF1D1E33),
              borderRadius: BorderRadius.circular(10.0),
            ),
          ),
        ),
        Expanded(
           child: Container(
            margin: EdgeInsets.all(15.0),
            decoration: BoxDecoration(
              color: Color(0xFF1D1E33),
              borderRadius: BorderRadius.circular(10.0),
            ),
          ),
        ),
        Expanded(
           child: Container(
            margin: EdgeInsets.all(15.0),
            decoration: BoxDecoration(
              color: Color(0xFF1D1E33),
              borderRadius: BorderRadius.circular(10.0),
            ),
          ),
        ),
      ],
     )
Stigmatic answered 10/7, 2020 at 16:42 Comment(0)
M
-1

Here's another option involving a for loop.

Column(
  children: <Widget>[
    for (var i = 0; i < widgets.length; i++)
      Column(
        children: [
          widgets[i], // The widget you want to create or place goes here.
          SizedBox(height: 10) // Any kind of padding or other widgets you want to put.
        ])
  ],
),
Monogamous answered 13/7, 2021 at 19:34 Comment(0)
W
-1

You can try this :


import 'package:flutter/material.dart';

class CustomColumn extends Column {
  CustomColumn({
    Key? key,
    MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
    MainAxisSize mainAxisSize = MainAxisSize.max,
    CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
    TextDirection? textDirection,
    VerticalDirection verticalDirection = VerticalDirection.down,
    TextBaseline? textBaseline,
    List children = const [],
    EdgeInsetsGeometry? rowPadding,
  }) : super(
          children: children.map((e) => Padding(padding : rowPadding ?? EdgeInsets.only(bottom:12), child : e)).toList(),
          key: key,
          mainAxisAlignment: mainAxisAlignment,
          mainAxisSize: mainAxisSize,
          crossAxisAlignment: crossAxisAlignment,
          textDirection: textDirection,
          verticalDirection: verticalDirection,
          textBaseline: textBaseline,
        );
}

and call


CustomColumn(children: [
                    item1,
                    item2,
                    item3,
                  ])
Wordage answered 11/8, 2021 at 9:31 Comment(0)
C
-1

You can use Padding to wrap each child widget, and then set the top or bottom of Padding.

If you don’t want to write a lot of the same numbers, you can do it like this:

Column(
  children: [
    child1, 
    child2, 
    ..., 
    childN
  ].map((e) => Padding(padding: EdgeInsets.only(top: 10), child: e)).toList()
);
Cyte answered 9/9, 2021 at 10:39 Comment(0)
B
-1

It's best to use the Wrap widget instead of a column or row.

Wrap( spacing: 10, runSpacing: 10, children:[], )

Bossuet answered 15/2, 2022 at 15:33 Comment(2)
This does not directly answer the poster's question. There are different opinions on what is the best.Xavier
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Greenroom

© 2022 - 2024 — McMap. All rights reserved.