Interface layout is mainly divided into two categories: layout components and positioning decoration weight components, our layout is basically nested with each other

  • 1. Layout class components
    • 1. Linear layout components
    • 2. Flexible layout components
    • 3. Streaming layout components
    • 4. Overlay layout components
  • 2, positioning decoration weight components
    • 1, the Container
    • 2, SizedBox
    • 3, wide height: AspectRatio
    • 4, FittedBox&FractionallySizedBox & ContainedBox
    • Expanded, Flexible, and Spacer

Here is the widget tree for the UI:

We will talk about Flutter layout from shallow to deep here

1, the Container

Container is a container-like component widely used in FLUTTER

The constructor

Container({this.alignment, this.padding, // Color, Color, Color, Color, Color, Color, Color, Color, Color, Color, Color, Color // Double width,// double height of the container,// BoxConstraints constraints, // this. Margin,// This.transform, // transform this.child,})Copy the code

attribute

  • Alignment: Child aligns property. You can set it to center, left, right, up, down, and so on.
  • Padding: Inside margin. Width and height contain padding values.
  • Color: indicates the background color.
  • -Leonard: Decorations, like borders, rounded corners, background images, etc. Do not set decoration and color for the Container at the same time. If you want to set color for the Container, you can set color for the decoration.
  • ForegroundDecoration, set foregroundDecoration.
  • Width: indicates the width.
  • Height:
  • Constraints: Constraints to the size range. Constraints has four properties: minWidth, minHeight, maxWidth, and maxHeight.
  • Margin: the outer margin.
  • Transform: Transform effect, such as flip, rotate, transform, etc.
  • Child: child component, optional.

The Container can be adjusted in two ways:

  • The Container tries to be large enough when it has no children. Unless constraints are unbounded, in which case the Container will try to be small enough.
  • The Container of the string node resizesaccording to the size of its children, but the Container constructor resizesaccording to the parameters in the constructor if the Container constructor contains width, height, and constraints.

Container(child: Text("Hello Flutter", // Text content style: TextStyle(fontSize: 20.0,color: Color.amber), // font style font size), alignment: Alignment of the word content Center, centerLeft, centerLeft, centerRight // bottomCenter, bottomLeft, BottomRight // Center on topCenter, left on topLeft, right on topRight width: 200, // wide height: 200, // high color: Color. Red, // color and decoration can not exist at the same time: Const EdgeInsets. FromLTRB (20.0, 20.0, 20.0, 20.0), // margin: const EdgeInsets. All (30.0), // margin: const EdgeInsets.Copy the code

(Decoration)

It supports linear or radial gradients, borders, rounded corners and shadows

The properties of Flutter Decoration can be: background color background image border rounded corner shadow gradient. The base class of Flutter Decoration has the following subclasses

  • BoxDecoration: Borders, rounded corners, shadows, shapes, gradients, background images
  • ShapeDecoration: Specify color and width, bottom line, rectangle, circle, stadium (vertical ellipse), and Angle (octagonal)
  • FlutterLogoDecoration: Flutter pictures
  • UnderlineTabindicator: underline
Const BoxDecoration({this.color,// background color this.image,// picture this.border,// Stroke this.borderRadius,// Round size this.boxShadow,// Shadow This gradient, / / gradient enclosing backgroundBlendMode, blend mode this. / / image shape = Rectangle,// Rectangle, boxShape. circle and borderRadius cannot be used at the same time})Copy the code

class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Container( margin: EdgeInsets. Only (top: 50.0, left: 120.0), // Constraints: BoxConstraints. TightFor (width: 200.0, height: 0) 150.0), // card size decoration: BoxDecoration(// background decoration: RadialGradient: colors: [color.red, color.orange], center: Alignment. TopLeft, radius:.98), boxShadow: [// card shadow (color: Colors. Black54, offset: offset (2.0, 2.0), blurRadius: 4.0)]), transform: matrix4.rotationz (.2), // Card alignment: Child: Text(// The card Text "Flutter Demo", style: TextStyle(color: colors.white, fontSize: 40.0),),); }}Copy the code

2, SizedBox

SizedBox: It can be used to set the spacing between widgets or to limit the size of child components.

Column(
      children: <Widget>[
        SizedBox(height: 30,),
        SizedBox(width: 200,height: 200,
          child: Container(
            width: 200,
            height: 200,
            color: Colors.red,
          ),
        ),
        SizedBox(height: 30,),
        SizedBox(width: 100,height: 100,
          child: Container(
            width: 200,
            height: 200,
            color: Colors.red,
          ),
        )
      ],
    );
Copy the code

As you can see, the code has a total of four SizedBox components, two are the function of setting spacing, two are the function of setting constraints

3. Linear layout

A linear layout is a horizontal or vertical arrangement of subcomponents. The linear layout of Flutter is achieved through rows and columns. Both Row and Column inherit from Flex, which we’ll cover in more detail in the Elastic Layout section.

  • A Row is a component that lays out its children horizontally,
  • A Column is a component that lays out the child components vertically

Ninety percent of the page layout in a project can be achieved through rows and columns.

1, the row

Row(
      children: <Widget>[
        Container(
          height: 50,
          width: 100,
          color: Colors.red,
        ),
        Container(
          height: 50,
          width: 100,
          color: Colors.green,
        ),
        Container(
          height: 50,
          width: 100,
          color: Colors.blue,
        ),
      ],
    );
Copy the code

2, the column

Column(
  children: <Widget>[
    Container(
      height: 50,
      width: 100,
      color: Colors.red,
    ),
    Container(
      height: 50,
      width: 100,
      color: Colors.green,
    ),
    Container(
      height: 50,
      width: 100,
      color: Colors.blue,
    ),
  ],
)
Copy the code

3. MainAxis and CrossAxis

There is a very important concept in Row and Column: MainAxis, which is the axis aligned with the component layout, and CrossAxis, which is the axis perpendicular to the axis.

For the Row component, the main axis is horizontal and the cross axis is vertical. Column is the opposite of Row, the main axis is vertical, and the cross axis is horizontal.

Now that you understand the spindle and cross axis concepts, take a look at the mainAxisAlignment property, which indicates the alignment of the main axis. The default value is start, which indicates the layout from the beginning of the component, where the starting position is related to the textDirection property. TextDirection indicates the layout direction of the text, and its values include LTR (left to right) and RTL (right to left). When textDirection = LTR, start indicates left. When textDirection = RTL, Start means right,

SpaceAround and spaceinstituted are:

  • SpaceAround: The first child control is half the distance from the start and the last child control is half the distance from the end of the other child controls.
  • Spaceinstituted: All evenly spaced.

Container(
      decoration: BoxDecoration(border: Border.all(color: Colors.black)),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          Container(
            height: 50,
            width: 100,
            color: Colors.red,
          ),
          Container(
            height: 100,
            width: 100,
            color: Colors.green,
          ),
          Container(
            height: 150,
            width: 100,
            color: Colors.blue,
          ),
        ],
      ),
    )
Copy the code

4. Flexible Layout (Flex)

Row and Column are inherited from Flex, and most of Flex’s capabilities were covered in the previous linear layout. We’re just adding a few points here.

  • Flexible: Flexible is a component that controls how Row, Column, Flex, and other sub-components are laid out.
  • 2. Expanded: Expanded inherits the word Flexible and the FIT parameter is fixed to flexfit. tight, that is, Expanded must (force) fill the remaining space
  • 3. Spacer: The essence of Spacer is also the implementation of Expanded. The difference with Expanded is: Expanded can set child controls, whereas Spacer’s child controls have a size of 0, so Spacer is suitable for padding child controls of Row, Column, and Flex

1, Flexible

The Flexible component allows Row, Column, and Flex children to fill the parent component. For example, a Row has three children, each side of which is 100 wide, and the middle one takes up the remaining space

Row(
      children: <Widget>[
        Container(
          color: Colors.blue,
          height: 50,
          width: 100,
        ),
        Flexible(
            child: Container(
              color: Colors.red,
              height: 50,
            )
        ),
        Container(
          color: Colors.blue,
          height: 50,
          width: 100,
        ),
      ],
    )
Copy the code

Again, there are 3 subcomponents, the first is 1/6, the second is 2/6, and the third is 3/6. The code is as follows

Column(
      children: <Widget>[
        Flexible(
          flex: 1,
          child: Container(
            color: Colors.blue,
            alignment: Alignment.center,
            child: Text('1 Flex/ 6 Total',style: TextStyle(color: Colors.white),),
          ),
        ),
        Flexible(
          flex: 2,
          child: Container(
            color: Colors.red,
            alignment: Alignment.center,
            child: Text('2 Flex/ 6 Total',style: TextStyle(color: Colors.white),),
          ),
        ),
        Flexible(
          flex: 3,
          child: Container(
            color: Colors.green,
            alignment: Alignment.center,
            child: Text('3 Flex/ 6 Total',style: TextStyle(color: Colors.white),),
          ),
        ),
      ],
    )

Copy the code

Subcomponent ratio = sum of current child control Flex/all flex subcomponents. The fit parameter in Flexible indicates the way to fill the remaining space, as follows:

  • Tight: must (compulsively) fill the remaining space.
  • Loose: Fill up the remaining space as much as possible, but don’t fill up.

These two don’t seem to make a lot of sense. What does it mean to fill up the remaining space as much as possible? When is it filled? See the example below

class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( children: <Widget>[ Container( color: Colors.blue, height: 50, width: 100, ), Flexible( child: Container( color: Colors.red, height: 50, child: Text('Container',style: TextStyle(color: Colors.white),), ) ), Container( color: Colors.blue, height: 50, width: 100, ), ], ); }}Copy the code

Add the Text child control to the red Container in the middle, so that the red Container is no longer full of space, and add the alignment to the Container as follows:

class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( children: <Widget>[ Container( color: Colors.blue, height: 50, width: 100, ), Flexible( child: Container( color: Colors.red, height: 50, alignment: Alignment.center, child: Text('Container',style: TextStyle(color: Colors.white),), ) ), Container( color: Colors.blue, height: 50, width: 100, ), ], ); }}Copy the code

2, Expanded

class Expanded extends Flexible {
  /// Creates a widget that expands a child of a [Row], [Column], or [Flex]
  /// so that the child fills the available space along the flex widget's
  /// main axis.
  const Expanded({
    Key key,
    int flex = 1,
    @required Widget child,
  }) : super(key: key, flex: flex, fit: FlexFit.tight, child: child);
}
Copy the code

Expanded inherits the word Flexible and the fit parameter is fixed to flexfit.tight, which means that Expanded must (force) fill the remaining space

3, Spacer

Spacer is also a weight component, and the source code is as follows:

@override
Widget build(BuildContext context) {
  return Expanded(
    flex: flex,
    child: const SizedBox.shrink(),
  );
}
Copy the code

The essence of Spacer is also an implementation of Expanded. The difference between Expanded and Expanded is that Expanded can set child controls, whereas Spacer’s child controls have a size of 0, so Spacer can be used to split gaps in child controls of Row, Column, and Flex as follows

Row(
  children: <Widget>[
    Container(width: 100,height: 50,color: Colors.green,),
    Spacer(flex: 2,),
    Container(width: 100,height: 50,color: Colors.blue,),
    Spacer(),
    Container(width: 100,height: 50,color: Colors.red,),
  ],
)
Copy the code

The three weights are summarized as follows:

  • Spacer is implemented through Expanded, which inherits from Flexible.
  • Filling the remaining space directly with Expanded is more convenient.
  • Spacer is used to split the gaps between the children of Row, Column, and Flex.

4. Streaming Layout (Wrap)

Wrap lays out the child components horizontally or vertically, and wraps itself when space runs out, known as streaming layout

Wrap(children: List. Generate (10, (I) {double w = 50.0 + 10 * I; return Container( color: Colors.primaries[i], height: 50, width: w, child: Text('$i'), ); }),)Copy the code

When we look at the Wrap source, we find a runAlignment property that feels like alignment.

The runAlignment attribute controls the alignment of each line in the Wrap cross alignment direction. The following is a diagram of the alignment in runAlignment 6

The difference between runAlignment and alignment:

  • Alignment: Indicates the alignment on each row in the main axis direction.
  • RunAlignment: Indicates the alignment of each row in the cross axis as a whole.

The spacing and runSpacing properties control the spacing between the Wrap spindle and cross-axis child controls

Generate (10, (I) {double w = 50.0 + 10 * I; return Container( color: Colors.primaries[i], height: 50, width: w, alignment: Alignment.center, child: Text('$i'), ); }),)Copy the code

5. Stack layout

The Stack layout component consists of the Stack and IndexedStack, and the Stack component displays the child components on top of each other, ascending according to the success of the child components

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 : The default position is to start with the top left corner. This property is the hardest to understand, because it divides into two definition of c-corner, which is used and which is not used. The no-jam situation is relatively easy to understand, and we will explain it in detail below
  • Fit: used to determine the size of the child Widget without the positioning of tourists, stackfit. loose means the child Widget is as big as it is, StackFit. Expand makes the child Widget as big as the parent
  • The default value is overflow. clip. If the child Widget exceeds the Stack, it will be truncated, and overflow. visible will be displayed
Stack(
      children: <Widget>[
        Container(
          height: 300,
          width: 300,
          color: Colors.red,
        ),
        Container(
          height: 200,
          width: 200,
          color: Colors.blue,
        ),
        Container(
          height: 100,
          width: 100,
          color: Colors.yellow,
        )
      ],
    );
Copy the code

IndexedStack

IndexedStack is a subclass of Stack, where Stack displays all the subcomponents of the index. IndexedStack displays only the subcomponents of the specified index through index.

class IndexedStackDemo extends StatefulWidget { @override _IndexedStackDemoState createState() => _IndexedStackDemoState(); } class _IndexedStackDemoState extends State<IndexedStackDemo> { int _index = 0; @override Widget build(BuildContext context) { return Column( children: <Widget>[ SizedBox(height: 50,), _buildIndexedStack(), SizedBox(height: 30,), _buildRow(), ], ); } _buildIndexedStack() { return IndexedStack( index: _index, children: <Widget>[ Center( child: Container( height: 300, width: 300, color: Colors.red, alignment: Alignment.center, child: Text('1'), ), ), Center( child: Container( height: 300, width: 300, color: Colors.green, alignment: Alignment.center, child: Text('2'), ), ), Center( child: Container( height: 300, width: 300, color: Colors.yellow, alignment: Alignment.center, child: Text('3'), ), ), ], ); } _buildRow() { return Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ RaisedButton( child: Text('1'), onPressed: (){ setState(() { _index = 0; }); }, ), RaisedButton( child: Text('2'), onPressed: (){ setState(() { _index = 1; }); }, ), RaisedButton( child: Text('3'), onPressed: (){ setState(() { _index = 2; }); }, ), ], ); }}Copy the code

6. AspectRatio

AspectRatio is a component with a fixed AspectRatio

Container(
          height: 300,
          width: 300,
          color: Colors.blue,
          alignment: Alignment.center,
          child: AspectRatio(
            aspectRatio: 2 / 1,
            child: Container(color: Colors.red,),
          ),
        )
Copy the code

7. Layout constraints

1. FittedBox

The FittedBox component does two main things, Scale and Position.

The FittedBox scales and adjusts the child’s position within its size to fit its size. FittedBox is similar to the Android ImageView in that it scales and positions images within its scope.

The layout is divided into two cases:

  • If there are external constraints, resize itself according to the external constraints, and then scale the child to layout according to the specified conditions.
  • Without external constraints, the specified scale and position attributes will have no effect, as with the child size.
 const FittedBox({
    Key key,
    this.fit = BoxFit.contain,
    this.alignment = Alignment.center,
    this.clipBehavior = Clip.hardEdge,
    Widget child,
  })  
Copy the code

There’s a new property called FIT

  • Boxfit. none, no padding mode
  • 2. Boxfit. fill: do not fill in proportion to width and height, and the content will not exceed the container scope
  • 3, BoxFit. Contain: Fill the container with an equal ratio of width to height
  • 4. Boxfit. cover: Fill the entire container mode to its original size. Contents may go out of container scope
  • 5. Boxfit.scaledown: Narrows the range down as appropriate

Container(
      color: Colors.amberAccent,
      width: 300.0,
      height: 300.0,
      child: FittedBox(
        fit: BoxFit.none,
        alignment: Alignment.topLeft,
          child: new Container(
            color: Colors.red,
            child: new Text("FittedBox"),
          )
      ),
    );
Copy the code

2, FractionallySizedBox

The FractionallySizedBox is a component that is relative to the parent component. It is used to adjust the layout size based on the width scaling factor and the height scaling factor, which may be larger than the parent component position.

const FractionallySizedBox({
    Key key,
    this.alignment = Alignment.center,
    this.widthFactor,
    this.heightFactor,
    Widget child,
  })
Copy the code
  • 1. WidthFactor: FractionallySizedBox the width of the component factors

    • widthFactor ! = null, the width of the child component is equal to the maximum width of the FractionallySizedBox component’s constraint times widthFractor
    • When widthFractor == null, the FractionallySizedBox component’s width constraint is passed to its children as is
  • 2. HeightFractor: height factor of the FractionallySizedBox component

    • heightFractor ! = null, the height of the subcomponent is equal to the maximum height of the constraint on the FractionallySizedBox component times the height of the heightFractor
    • When heightFractor == null, the height constraint of the FractionallySizedBox component is passed on to the child components intact
Container(
      height: 200,
      width: 200,
      color: Colors.blue,
      child: FractionallySizedBox(
        widthFactor: .8,
        heightFactor: .3,
        child: Container(
          color: Colors.red,
        ),
      ),
    )
Copy the code

3, ContainedBox

A ContainedBox is a layout that has a set of limits that its children cannot exceed, such as a maximum height and a minimum width

ConstrainedBox({
    Key key,
    @required this.constraints,
    Widget child,
  })
Copy the code

Constraints: Additional constraints added to the child, of type BoxConstraints. What does BoxConstraints do? In fact, very simple, is to limit the maximum and minimum width and height. By the way, double-.infinity is legal for widget layout, so for example, to maximize the width of the widget, you can set the width to double-.infinity.

8 cases,

This case is from: flutter.cn/docs/develo…

We’re going to do this interface

The specific code is as follows

class demoWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Container( height: 300, child: Card( color: Colors.white, margin: EdgeInsets.fromLTRB(10, 0, 10, 0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ topWidget(), starWidget(), iconWidget()], ), ) ); } } class topWidget extends StatelessWidget { final mainImage = Container( margin: EdgeInsets.fromLTRB(10, 10, 0, 0), child: Image.asset( 'images/pavlova.jpg', fit: BoxFit.fill, width: 130, height: 130,),); @override Widget build(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ mainImage, Flexible( child: rightWidget() ), ], ); } } class rightWidget extends StatelessWidget { final titleText = Container( padding: EdgeInsets. FromLTRB (10, 15, 0, 0), child: Text('Strawberry Pavlova', style: TextStyle(letterSpacing: 0.5, fontSize: 17,),),); final subTitle = Container( padding: EdgeInsets.fromLTRB(10, 10, 10, 10), child: Text( 'Pavlova is a meringue-based dessert named after the Russian ballerina ' 'Anna Pavlova. Pavlova features a crisp crust and soft, light inside, ' 'topped with fruit and whipped cream.', style: TextStyle( fontSize: 12, ), ), ); @override Widget build(BuildContext context) { return Container( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [titleText,subTitle], ), ); } } class starWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Container( padding:  EdgeInsets.fromLTRB(10, 10, 10, 10), child: Row( children: [ Icon(Icons.star, color: Colors.green[500]), Icon(Icons.star, color: Colors.green[500]), Icon(Icons.star, color: Colors.green[500]), Icon(Icons.star, color: Colors.black), Icon(Icons.star, color: Colors.black), ], ), ); } } class iconWidget extends StatelessWidget { final descTextStyle = TextStyle( color: Colors.black, fontSize: 18, height: 1.2); @override Widget build(BuildContext context) { return Container( child: Container( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Column( children: [ Icon(Icons.kitchen, color: Colors.green[500]), Text('PREP:',style: descTextStyle), Text('25 min',style: descTextStyle), ], ), Column( children: [ Icon(Icons.timer, color: Colors.green[500]), Text('COOK:',style: descTextStyle), Text('1 hr',style: descTextStyle), ], ), Column( children: [ Icon(Icons.restaurant, color: Colors.green[500]), Text('FEEDS:',style: descTextStyle), Text('4-6',style: descTextStyle), ], ), ], ), ), ); }}Copy the code

Code address: github.com/SunshineBro…