Flutter multiple child layout widgets


1) Row
Row is a layout widget in flutter which aligns its children horizontally. It can have multiple child widgets. Child widget can also be a Row or Column widget. Children of Row widget are not scrollable. If you want scrollable widgets then use ListView. If we add a large number of children in Row widget which can not be fit in Row then we see an overflow message.
Constructor:
Row({
Key key,
MainAxisAlignment mainAxisAlignment: MainAxisAlignment.start,
MainAxisSize mainAxisSize: MainAxisSize.max,
CrossAxisAlignment crossAxisAlignment: CrossAxisAlignment.center,
TextDirection textDirection,
VerticalDirection verticalDirection: VerticalDirection.down,
TextBaseline textBaseline,
List<Widget> children: const []
})

mainAxisAlignment property runs horizontally and crossAxisAlignment property runs vertically.
output

Here is different properties explained for main axis and cross axis alignment:
  1. start: it will align children at the start of the axis direction.
  2. center: It will align children at the center of the axis.
  3. end: It will align children at the end of the axis.
  4. spaceBetween: It will add space between children evenly.
  5. spaceAround:It will add the space between the children evenly and half of that space before and after the first and last children widget.
  6. spaceEvenly: It will add the space between the children evenly and before and after the first and last children widget.

2) Column
Column is a layout widget in flutter which aligns its children vertically. It can have multiple child widgets. Child widget can also be a Row or Column widget. Children of Column widget are not scrollable. If you want scrollable widgets then use ListView. If we add a large number of children in Column widget which can not be fit in column then we see an overflow message.
Constructor:
Column(
{Key key,
MainAxisAlignment mainAxisAlignment: MainAxisAlignment.start,
MainAxisSize mainAxisSize: MainAxisSize.max,
CrossAxisAlignment crossAxisAlignment: CrossAxisAlignment.center,
TextDirection textDirection,
VerticalDirection verticalDirection: VerticalDirection.down,
TextBaseline textBaseline,
List<Widget> children: const <Widget>[]}
)
output

Here is different properties explained for main axis and cross axis alignment:
  1. start: it will align children at the start of the axis direction.
  2. center: It will align children at the center of the axis.
  3. end: It will align children at the end of the axis.
  4. spaceBetween: It will add space between children evenly.
  5. spaceAround: It will add the space between the children evenly and half of that space before and after the first and last children widget.
  6. spaceEvenly: It will add the space between the children evenly and before and after the first and last children widget.
3) Expanded
Expanded works with Flex/Flexbox layout and is great for distributing space between multiple items. It expands the child of the Row, Column or Flex widget such that the child fills maximum available space.
Example:
Center(
       child: Row(
         children: <Widget>[
           Container(
             color: Colors.blue,
             height: 100,
             width: 100,
           ),
           Expanded(
             child: Container(
               color: Colors.orange,
               height: 100,
             ),
           ),
           Container(
             color: Colors.blue,
             height: 100,
             width: 100,
           ),
         ],
       ),
   )

If multiple children are expanded, the available space is divided among them according to the flex factor.
Example:
Center(
       child: Row(
         children: <Widget>[
           Expanded(
             flex: 2,
             child: Container(
     color: Colors.blue,
     height: 100,
     width: 100,
           )),
           Expanded(
             flex: 3,
             child: Container(
               color: Colors.orange,
               height: 100,
     width: 100
             ),
           ),
           Expanded(
             flex: 4,
             child: Container(
               color: Colors.blue,
                  height: 100,
     width: 100
             ),
           ),
         ],
       ),
   )

4) ListView
A scrollable list of widgets arranged linearly. It shows children one by one in a scrollable direction. when we want to create a list recursively without writing code again and again then ListView.builder is used instead of ListView.
Constructor of ListView:
ListView({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsetsGeometry padding,
double itemExtent,
bool addAutomaticKeepAlives: true,
bool addRepaintBoundaries: true,
bool addSemanticIndexes: true,
double cacheExtent,
List<Widget> children: const <Widget>[],
int semanticChildCount,
DragStartBehavior dragStartBehavior: DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.manual,
String restorationId,
Clip clipBehavior: Clip.hardEdge
})

Example of ListView:
ListView(
       children: <Widget>[
         Text('Sunday'),
         Text('Monday'),
         Text('Tuesday'),
       ],
     )

The above constructor is useful for a small size of list because it takes List as children. To work with lists having a large number of items, we need to use ListView.builder. The difference between ListView and ListView.builder is that ListView creates all items at once whereas ListView.builder creates items when they are scrolled onto the screen.
Constructor of ListView.builder:
ListView.builder({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsetsGeometry padding,
double itemExtent,
@required IndexedWidgetBuilder itemBuilder,
int itemCount,
bool addAutomaticKeepAlives: true,
bool addRepaintBoundaries: true,
bool addSemanticIndexes: true,
double cacheExtent,
int semanticChildCount,
DragStartBehavior dragStartBehavior: DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.manual,
String restorationId,
Clip clipBehavior: Clip.hardEdge
})

The ListView.builder constructor takes an IndexedWidgetBuilder, which builds the children on demand.
Example:
final List<String> entries = <String>['A', 'B', 'C'];

ListView.builder(
       itemCount: entries.length,
       itemBuilder: (BuildContext context, int index) {
      return Text('${entries[index]}');
  }
)

Similarly ListView.separated is useful when you want to add a separator in between children of the List.
Constructor of ListView.separated:
ListView.separated({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsetsGeometry padding,
@required IndexedWidgetBuilder itemBuilder,
@required IndexedWidgetBuilder separatorBuilder,
@required int itemCount,
bool addAutomaticKeepAlives: true,
bool addRepaintBoundaries: true,
bool addSemanticIndexes: true,
double cacheExtent,
DragStartBehavior dragStartBehavior: DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.manual,
String restorationId,
Clip clipBehavior: Clip.hardEdge
})

The ListView.separated constructor takes two IndexedWidgetBuilders: itemBuilder builds child items on demand, and separatorBuilder similarly builds separator children which appear in between the child items. This constructor is appropriate for list views with a fixed number of children.
Example:
final List<String> entries = <String>['A', 'B', 'C'];

ListView.separated(
 itemCount: entries.length,
 itemBuilder: (BuildContext context, int index) {
   return Container(
     height: 50,
     color: Colors.orange,
     child: Center(child: Text('${entries[index]}')),
   );
 },
 separatorBuilder: (BuildContext context, int index) => const Divider(),
);

Horizontal ListView:
To create horizontal ListView, specify scrollDirection as horizontal.
Example:
ListView.builder(
       scrollDirection: Axis.horizontal,
       itemBuilder: (context, index) {
         return Container(
           margin: const EdgeInsets.symmetric(horizontal: 1.0),
           color: Colors.tealAccent,
           child: Text('$index'),
         );
       },
     )

5) GridView
GridView is a scrollable 2D array of widgets. The main axis direction of a grid is the direction in which it scrolls. We can define the direction only in which it can scroll using scrollDirection property.
The most frequently used grid layout is GridView.count
i) GridView.count:
Constructor of GridView.count:
GridView.count({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsetsGeometry padding,
@required int crossAxisCount,
double mainAxisSpacing: 0.0,
double crossAxisSpacing: 0.0,
double childAspectRatio: 1.0,
bool addAutomaticKeepAlives: true,
bool addRepaintBoundaries: true,
bool addSemanticIndexes: true,
double cacheExtent,
List<Widget> children: const <Widget>[],
int semanticChildCount,
DragStartBehavior dragStartBehavior: DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.manual,
String restorationId,
Clip clipBehavior: Clip.hardEdge
})

Creates a scrollable, 2D array of widgets with a fixed number of tiles in the cross axis. Some of the important properties are:

scrollDirection:It specifies the direction in which GridView will scroll. By default, it scrolls in a vertical direction.
shrinkWrap:If the scroll view does not shrink wrap, then the scroll view will expand to the maximum allowed size in the scrollDirection. If the scroll view has unbounded constraints in the scrollDirection, then shrinkWrap must be true.
crossAxisCount:It specifies the number of columns in a grid view.
crossAxisSpacing:It specifies the spacing between each child widget listed in the cross axis.
mainAxisSpacing:It specifies the number of pixels between each child widget listed in the main axis.

Example:
GridView.count(
crossAxisCount: 2 ,
children: List.generate(10,(index){
  return Container(
    child: Card(
      color: Colors.blue,
    ),
  );
}),
)

ii) GridView.builder
Constructor:
GridView.builder(
{Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsetsGeometry padding,
@required SliverGridDelegate gridDelegate,
@required IndexedWidgetBuilder itemBuilder,
int itemCount,
bool addAutomaticKeepAlives: true,
bool addRepaintBoundaries: true,
bool addSemanticIndexes: true,
double cacheExtent,
int semanticChildCount,
DragStartBehavior dragStartBehavior: DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.manual,
String restorationId,
Clip clipBehavior: Clip.hardEdge}
)

Creates a scrollable, 2D array of widgets that are created on demand. This constructor is appropriate for grid views with a large (or infinite) number of children because the builder is called only for those children that are actually visible.

itemCount:It specifies the item count.
gridDelegate:It determines the grid or its divider. Its argument should not be null.
itemBuilder:It is used to create items that will be displayed on the grid view. It will be called only when the indices >= 0 and indices < itemCount.

Example:
final List<String> entries = <String>['A', 'B', 'C', 'D', 'E', 'F'];
  GridView.builder(
             itemCount: entries.length,
             gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                 crossAxisCount: 2,
             ),
             itemBuilder: (BuildContext context, int index){
               return Text('${entries[index]}');
             },
           )

iii) GridView.extent()
Creates a scrollable, 2D array of widgets with tiles that each have a maximum cross-axis extent.
Constructor:
GridView.extent(
{Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsetsGeometry padding,
@required double maxCrossAxisExtent,
double mainAxisSpacing: 0.0,
double crossAxisSpacing: 0.0,
double childAspectRatio: 1.0,
bool addAutomaticKeepAlives: true,
bool addRepaintBoundaries: true,
bool addSemanticIndexes: true,
double cacheExtent,
List<Widget> children: const <Widget>[],
int semanticChildCount,
DragStartBehavior dragStartBehavior: DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.manual,
String restorationId,
Clip clipBehavior: Clip.hardEdge}
)

Example:
GridView.extent(
           primary: false,
           padding: const EdgeInsets.all(16),
           crossAxisSpacing: 10,
           mainAxisSpacing: 10,
           maxCrossAxisExtent: 200.0,
           children: <Widget>[
             Container(
               padding: const EdgeInsets.all(8),
               child: const Text('A', style: TextStyle(fontSize: 20)),
               color: Colors.orange,
             ),
             Container(
               padding: const EdgeInsets.all(8),
               child: const Text('B', style: TextStyle(fontSize: 20)),
               color: Colors.blue,
             ),
             Container(
               padding: const EdgeInsets.all(8),
               child: const Text('C', style: TextStyle(fontSize: 20)),
               color: Colors.blue,
             ),
             Container(
               padding: const EdgeInsets.all(8),
               child: const Text('D', style: TextStyle(fontSize: 20)),
               color: Colors.orange,
             ),
           ],
         )

6) Stack
Stack is useful when you want to overlap multiple children in a single screen. Each member of a Stack widget is either positioned or non-positioned.

i) Positioned Widget:
A child of Stack wrapped with Positioned Widget that has at least one non-null property. It works with a combination of parameters - vertical (top, bottom, height) and horizontal (left, right and width) to position the widgets within the Stack. If not positioned widget, Align Widget is used to position the member of Stack.

ii) Non-positioned Widget:
If Stack's member is not wrapped with Align or Positioned Widget, then it is considered a Non-positioned widget. Non-positioned widgets end up on the screen based on Stack's alignment property. By default, the top left corner on the screen.
Example:
Stack(
  alignment: Alignment.topLeft,
  children: <Widget>[
    Positioned(
      top: 100,
      left: 100,
      child: Container(
        height: 300,
        width: 300,
        child: Center(child: Text('Positioned')),
        color: Colors.orange,
      ),
    ),
    Align(
      alignment: Alignment.topCenter,
      child: Container(
        height: 300,
        width: 300,
        child: Center(child: Text('Aligned')),
        color: Colors.red,
      ),
    ),
    Container(
      height: 100,
      width: 100,
      child: Center(child: Text('Non-Positioned')),
        color: Colors.blue,
    ),
  ],
)

Output:
output