The LinearLayout is implemented with rows and columns, similar to the LinearLayout control in Android. Both rows and columns are inherited from Flex. Flex allows child components to allocate proportionally to their parent container space. A layout that automatically folds outside the screen is called a streaming layout. Flow layout is supported in Flutter through Wrap and Flow. The cascading layout is similar to the Android Frame layout in that child components are positioned four corners from their parent container. Absolute positioning allows child components to be stacked (in the order declared in the code). The Stack and the Stack are Positioned in conjunction with the two components of the Flutter to achieve absolute positioning. The Stack allows the child components to Stack, while the child components are Positioned according to the four corners of the Stack.

One, linear layout

1.1 Spindle and cross axis

For linear layout, there are main axis and cross axis. If the layout is horizontal, then the main axis is horizontal and the cross axis is vertical. If the layout is vertical, then the main axis is vertical and the cross axis is horizontal. In linear layouts, there are two enumeration classes that define alignment, MainAxisAlignment and CrossAxisAlignment, which stand for spindle alignment and cross-axis alignment, respectively.

Spindle alignment —- MainAxisAlignment

CrossAxisAlignment —- CrossAxisAlignment

Below is MainAxisAlignment, which is also an enumeration class.

enum MainAxisAlignment {
  start,
  end,
  center,
  spaceBetween,
  spaceAround,
  spaceEvenly,
}
Copy the code

Start —- Place the child widgets as close as possible to the start of the main axis. If this value is used horizontally, [TextDirection] must be available to determine whether the starting point is left or right; If this value is used in a VerticalDirection, [VerticalDirection] must be available to determine whether the starting point is top or bottom.

End —- Place the child Widget as close to the end of the spindle as possible. If you use this value horizontally, [TextDirection] must be available to determine whether the end is left or right; If you use this value in the VerticalDirection, you must use [VerticalDirection] to determine whether the end is top or bottom.

Center —- Place the child widgets as close to the center of the spindle as possible.

SpaceBetween —- places free space evenly between the sub-widgets.

SpaceAround —- evenly places the available space between the sub-widgets and between the half of the space before and after the first and last sub-widgets. This paragraph of text is a bit convoluted, then look at the example is very clear.

Spaceinstituted —- places free spaceEvenly between subwidgets and before and after the first and last subwidgets.

Next is CrossAxisAlignment, which is also an enumeration class.

enum CrossAxisAlignment {
  start,
  end,
  center,
  stretch,
  baseline,
}
Copy the code

Start —- Aligns the beginning edge of the child with the beginning side of the cross axis. If this value is used horizontally, [TextDirection] must be available to determine whether the starting point is left or right; If this value is used in a VerticalDirection, [VerticalDirection] must be available to determine whether the starting point is top or bottom.

End —- Place the child Widget as close as possible to the end of the cross axis. If you use this value horizontally, [TextDirection] must be available to determine whether the end is left or right; If you use this value in the VerticalDirection, you must use [VerticalDirection] to determine whether the end is top or bottom.

Center —- Place the child Widget so that its center aligns with the center of the cross axis. This is the default horizontal alignment.

Stretch —- requires sub-widgets to fill the cross axis.

Baseline —- Place the child Widget along the cross axis so that its baseline matches. If the spindle is vertical, consider this value to be [start] (because the baseline is always horizontal).

1.2 the Row and Column

The linear layout is implemented with rows and columns in the Flutter.

1.2.1 Row

Row is the Row layout.

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 <Widget>[],
  })
Copy the code

MainAxisAlignment —- indicates how the child components are aligned within the horizontal space occupied by the Row. If the mainAxisSize value is mainAxissize.min, this property is meaningless because the width of the child component is equal to the width of the Row. This property is only meaningful if the value of mainAxisSize is mainAxisSize.max.

TextDirection —- indicates the layout order of horizontal sub-components (left-to-right or right-to-left). The default is the textDirection of the current Locale (for example, left-to-right for Chinese and English, and right-to-left for Arabic).

The default is MainAxissize.max, which means as much horizontal space as possible. No matter how much horizontal space the child widgets actually occupy, the width of the Row is always the same as the maximum horizontal width. MainAxisSize. Min means to occupy as little horizontal space as possible, and when the subcomponents do not occupy the remaining horizontal space, the actual width of the Row is equal to the horizontal space occupied by all the subcomponents.

VerticalDirection —- indicates the vertical alignment direction of the rows. The default value is verticaldirection. down, which indicates that the rows are aligned from top to bottom.

CrossAxisAlignment —- indicates the alignment of child components in the vertical direction, with the height of the Row equal to the height of the highest child element in the child component.

Children —- Array of child components.

TextBaseline —- is used to align horizontal lines of text.

TextBaseline is an enumeration class that includes Alphabetic and ideographic.

enum TextBaseline {
  alphabetic,
  ideographic,
}
Copy the code

Alphabetic —- is used to align the horizontal line at the bottom of the glyph of alphabetic characters.

Ideographic —- Horizontal lines used to align ideographic characters.

1.2.2 the Column

Like Row, Column is a Column layout.

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>[],
  }) 
Copy the code

Let’s look at an example.

import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Home Page"), ), body: Column(mainAxisAlignment: MainAxisAlignment.start, children: < Widget>[ Row(mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ Text( 'Test1', ), Text( 'Test2', ), Text( 'Test3', ), Text( 'Test4', ) ]), Row(mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ Text( 'Test1', ), Text( 'Test2', ), Text( 'Test3', ), Text( 'Test4', ) ]), Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'Test1', ), Text( 'Test2', ), Text( 'Test3', ), Text( 'Test4', ) ]), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Text( 'Test1', ), Text( 'Test2', ), Text( 'Test3', ), Text( 'Test4', ) ]), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[ Text( 'Test1', ), Text( 'Test2', ), Text( 'Test3', ), Text( 'Test4', ) ]), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Text( 'Test1', ), Text( 'Test2', ), Text( 'Test3', ), Text( 'Test4', ) ]), ])); }}Copy the code

Below is a screenshot of the corresponding Row layout, MainAxisAlignment understanding should be clear.



Next, modify the Demo to look at the cross axis control.

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
        ),
        body: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
              Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    Text(
                      'Test1',
                      textScaleFactor: 3.0,
                    ),
                    Text(
                      'Test2',
                    ),
                    Text(
                      'Test3',
                    ),
                    Text(
                      'Test4',
                    )
                  ]),
              Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Text(
                      'Test1',
                      textScaleFactor: 3.0,
                    ),
                    Text(
                      'Test2',
                    ),
                    Text(
                      'Test3',
                    ),
                    Text(
                      'Test4',
                    )
                  ]),
              Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  crossAxisAlignment: CrossAxisAlignment.end,
                  children: <Widget>[
                    Text(
                      'Test1',
                      textScaleFactor: 3.0,
                    ),
                    Text(
                      'Test2',
                    ),
                    Text(
                      'Test3',
                    ),
                    Text(
                      'Test4',)]])); }}Copy the code



To study the cross shaft crossAxisAlignment set to crossAxisAlignment. The effect of stretch, it requires that the child widgets to fill the cross axis. For Row, the cross axis is the vertical direction.

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
        ),
        body: Row(
            mainAxisAlignment: MainAxisAlignment.start,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              Text(
                'Test1',
                textScaleFactor: 3.0,
              ),
              Text(
                'Test2',
              ),
              Text(
                'Test3',
              ),
              Text(
                'Test4'))); }}Copy the code

Two, flexible layout

Let’s first look at how Flex is used, and then look at how the component Expanded is used.

2.1 the Flex

Flex components can be arranged horizontally or vertically. If you know the main axis direction, it’s easier to use Row or Column. Row and Column inherit from Flex and take almost the same arguments, so you can use Row or Column almost anywhere you can use Flex. Flex is powerful on its own, but it can also work with Expanded components to achieve flexible layouts.

Flex({
    Key key,
    @required this.direction,
    this.mainAxisAlignment = MainAxisAlignment.start,
    this.mainAxisSize = MainAxisSize.max,
    this.crossAxisAlignment = CrossAxisAlignment.center,
    this.textDirection,
    this.verticalDirection = VerticalDirection.down,
    this.textBaseline,
    List<Widget> children = const <Widget>[],
  })
Copy the code

Row has one more direction than Column and Row. It is an elastic layout direction. Row defaults to horizontal and Column to vertical. Modify the above example to replace Row and Column with Flex, and you can see that the effect is exactly the same.

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
        ),
        body: Flex(
            mainAxisAlignment: MainAxisAlignment.start,
            direction: Axis.vertical,
            children: <Widget>[
              Flex(
                  mainAxisAlignment: MainAxisAlignment.start,
                  direction: Axis.horizontal,
                  children: <Widget>[
                    Text(
                      'Test1',
                    ),
                    Text(
                      'Test2',
                    ),
                    Text(
                      'Test3',
                    ),
                    Text(
                      'Test4',
                    )
                  ]),
              Flex(
                  mainAxisAlignment: MainAxisAlignment.end,
                  direction: Axis.horizontal,
                  children: <Widget>[
                    Text(
                      'Test1',
                    ),
                    Text(
                      'Test2',
                    ),
                    Text(
                      'Test3',
                    ),
                    Text(
                      'Test4',)]])); }}Copy the code

Look at the above code in action:

2.2 Expanded

You can scale out the space occupied by Row, Column, and Flex child components. This is similar to the weight of controls in Android.

const Expanded({
    Key key,
    int flex = 1.@required Widget child,
  })
Copy the code

Flex —- is the elastic coefficient; if it is 0 or NULL, the child is inelastic, that is, the space that will not be taken up by expansion. If greater than 0, all of the Expanded splits the entire available space of the spindle in proportion to its Flex.

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
        ),
        body: Flex(
            mainAxisAlignment: MainAxisAlignment.start,
            direction: Axis.vertical,
            children: <Widget>[
              Expanded(
                flex: 2,
                child: Flex(
                    mainAxisAlignment: MainAxisAlignment.start,
                    direction: Axis.horizontal,
                    children: <Widget>[
                      Text(
                        'Test1',
                      ),
                      Text(
                        'Test2',
                      ),
                      Text(
                        'Test3',
                      ),
                      Text(
                        'Test4',
                      )
                    ]),
              ),
              Expanded(
                flex: 2,
                child: Flex(
                    mainAxisAlignment: MainAxisAlignment.end,
                    direction: Axis.horizontal,
                    children: <Widget>[
                      Text(
                        'Test1',
                      ),
                      Text(
                        'Test2',
                      ),
                      Text(
                        'Test3',
                      ),
                      Text(
                        'Test4'))))))); }}Copy the code

So let’s see what happens

Three, flow layout

When using Row and Colum, an overflow error is reported if the child widget is out of screen range. We call a layout that automatically folds out of the screen a streaming layout, which is supported in Flutter through Wrap and Flow.

Tweaking the code in the previous example a little, we see the overflow problem.

Text(
    'Test1'* 200,),Copy the code

3.1 Wrap

The word wrap itself means “parcel”, and using a wrap to wrap a sub-widget can achieve streaming layout.

Wrap({
    Key key,
    this.direction = Axis.horizontal,
    this.alignment = WrapAlignment.start,
    this.spacing = 0.0.this.runAlignment = WrapAlignment.start,
    this.runSpacing = 0.0.this.crossAxisAlignment = WrapCrossAlignment.start,
    this.textDirection,
    this.verticalDirection = VerticalDirection.down,
    List<Widget> children = const <Widget>[],
  }) 
Copy the code

We’ve already seen most of the fields.

Spacing —- Spacing of sub-widgets in the main axis direction

RunSpacing —- Spacing along the cross axis

RunAlignment —- Alignment in the cross-axis direction

Here is the Demo code

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
        ),
        body: Flex(
            mainAxisAlignment: MainAxisAlignment.start,
            direction: Axis.vertical,
            children: <Widget>[
              Expanded(
                flex: 2,
                child: Wrap(
                    spacing: 8.0,
                    runSpacing: 4.0,
                    alignment: WrapAlignment.start,
                    runAlignment: WrapAlignment.center,
                    children: <Widget>[
                      Text(
                        'Test1' * 30,
                      ),
                      Text(
                        'Test2',
                      ),
                      Text(
                        'Test3',
                      ),
                      Text(
                        'Test4',
                      )
                    ]),
              ),
              Expanded(
                flex: 2,
                child: Flex(
                    mainAxisAlignment: MainAxisAlignment.end,
                    direction: Axis.horizontal,
                    children: <Widget>[
                      Text(
                        'Test1',
                      ),
                      Text(
                        'Test2',
                      ),
                      Text(
                        'Test3',
                      ),
                      Text(
                        'Test4'))))))); }}Copy the code

The running effect is as follows

3.2 the Flow

Flow needs to implement the location transformation of the sub-widgets itself.

Flow({
    Key key,
    @required this.delegate,
    List<Widget> children = const <Widget>[],
  }) 
Copy the code

Delegate —- A delegate that controls the appearance of the flow layout

For example, the following code to achieve color block drawing, only draw a line.

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
        ),
        body: Flow(
          delegate: TestFlowDelegate(margin: EdgeInsets.all(10.0)),
          children: <Widget>[
            new Container(
              width: 50.0,
              height: 50.0,
              color: Colors.red,
            ),
            new Container(
              width: 50.0,
              height: 50.0,
              color: Colors.green,
            ),
            new Container(
              width: 50.0,
              height: 50.0,
              color: Colors.blue,
            ),
            new Container(
              width: 50.0,
              height: 50.0,
              color: Colors.yellow,
            ),
            new Container(
              width: 50.0,
              height: 50.0,
              color: Colors.brown,
            ),
            new Container(
              width: 50.0,
              height: 50.0, color: Colors.purple, ), ], )); }}class TestFlowDelegate extends FlowDelegate {
  EdgeInsets margin = EdgeInsets.zero;

  TestFlowDelegate({this.margin});

  @override
  void paintChildren(FlowPaintingContext context) {
    var x = margin.left;
    var y = margin.top;
    // Calculate the location of each child widget
    for (int i = 0; i < context.childCount; i++) {
      if (x < context.size.width) {
        context.paintChild(i,
            transform: new Matrix4.translationValues(x, y, 0.0)); } x += context.getChildSize(i).width + margin.left + margin.right; }}@override
  getSize(BoxConstraints constraints) {
    // Specify the size of the Flow
    return Size(double.infinity, 70.0);
  }

  @override
  bool shouldRepaint(FlowDelegate oldDelegate) {
    returnoldDelegate ! =this; }}Copy the code

The running effect is as follows:

Four, stacked layout

The stacked layout includes Stack, glimpse.

4.1 the Stack

The word Stack is familiar to programmers. First in, second out. So in Flutter it means that the Stack layout is stackable, and the top layer floats above the bottom.

Stack({
    Key key,
    this.alignment = AlignmentDirectional.topStart,
    this.textDirection,
    this.fit = StackFit.loose,
    this.overflow = Overflow.clip,
    List<Widget> children = const <Widget>[],
  }) 
Copy the code

Alignment —- How to align unlocated and partially located sub-widgets in the Stack. Partial positioning refers to not positioning on an axis: left and right are the horizontal axis, while top and bottom are the vertical axis. Positioning on an axis is considered as long as a positioning attribute on an axis is included.

Fit —- Determine how unlocated sub-widgets fit into the size of the Stack

enum StackFit {
  /// The constraints passed from the parent to the Stack are relaxed.
  /// For example, if the Stack has a constraint that forces it to be 350x600,
  /// This will allow unlocated child widgets in the Stack to have any width from 0 to 350 and any height from 0 to 600.
  loose,
  /// Constraints passed from the parent to the Stack are narrowed to the maximum allowable limit.
  /// For example, if the Stack is loosely constrained and its width is in the range of 10 to 100 and its height is in the range of 0 to 600,
  /// Then the sizes of unlocated child elements in the Stack are all set to 100 pixels wide and 600 high.
  expand,
  /// Constraints passed from their parent to the Stack are passed unmodified to unlocated child widgets.
  passthrough,
}
Copy the code

Overflow —- Determines how to display subwidgets that exceed the display space of the Stack

enum Overflow {
  ///Beyond part visible
  visible,
  /// The excess will be clipped
  clip,
}
Copy the code

Let’s look at an example of how to use Stack.

class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Home Page"), ), body: ConstrainedBox( constraints: BoxConstraints.expand(), child: Stack( alignment: Alignment.center, children: <Widget>[ Container( child: Text( "Text1", style: TextStyle(color: Color. white), textScaleFactor: 3.0,), Color: color. red,), Container(Child: Text("Text2", style: TextStyle(color: Colors.white)), color: Colors.blue, ), ], ), )); }}Copy the code

Run the following screenshot

4.1 Positioned

C-21 would offer a small glimpse of space, so its Field includes left, top, width and height, as well as right and bottom. The first four would be enough.

const Positioned({
    Key key,
    this.left,
    this.top,
    this.right,
    this.bottom,
    this.width,
    this.height,
    @required Widget child,
  }) 
Copy the code

The width and height of space are slightly different from those of other Spaces in that they are used to position the component in conjunction with left, top, right and bottom. For example, in a horizontal orientation you can only specify two of the properties left, right and width. If left and width are specified, right is automatically calculated (left + width). If three properties are specified at the same time, an error is reported.

In the Demo example below, the Stack alignment property is not available due to the presence of partially Positioned tourists.

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
        ),
        body: ConstrainedBox(
          constraints: BoxConstraints.expand(),
          child: Stack(
            alignment: Alignment.center,
            overflow: Overflow.clip,
            children: <Widget>[
              Container(
                child: Text(
                  "Text1",
                  style: TextStyle(color: Colors.white),
                  textScaleFactor: 3.0,
                ),
                color: Colors.red,
              ),
              Container(
                child: Text("Text2", style: TextStyle(color: Colors.white)),
                color: Colors.blue,
              ),
              Positioned(
                left: 20.0,
                top: 20.0,
                child: Text("Text3"),
              ),
              Positioned(
                right: 20.0,
                child: Text("Text4")))))))); }}Copy the code

The results