banner
jzman

jzman

Coding、思考、自觉。
github

Detailed Explanation of Flex Layout in Flutter Series

PS: Long-term persistence is a difficult thing.

Flutter is a cross-platform UI framework launched by Google, which can quickly build high-quality applications on Android and iOS. Its main features include the ability for rapid development, expressive and flexible UI, and good native performance. This article mainly introduces the Flex layout in Flutter, as follows:

  1. Basics of Flex
  2. Common Settings of Flex
  3. Row and Column
  4. Expanded and Flexible
  5. Spacer
  6. Summary

Basics of Flex#

The Flex layout method has been widely used in front-end and mini-program development. If you have previously learned about Flex layout, it is quite similar in Flutter. The diagram of the Flexible Box is as follows:

image

For an introduction to this image, please refer to the previous article:

The Flex Widget can set the main axis direction. If you know the main axis direction, you can directly use Row or Column. The Flex Widget cannot scroll; if scrolling is involved, you can try using ListView. If the content of the Flex Widget exceeds its width and height, a yellow-black striped warning will be displayed. For example, the error message that appears in the horizontal direction is as follows:

I/flutter (14749): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter (14749): The following assertion was thrown during layout:
I/flutter (14749): A RenderFlex overflowed by 440 pixels on the right.

The error display is as follows:

image

Common Settings of Flex#

The common properties of Flex are as follows:

  1. direction
  2. mainAxisAlignment
  3. mainAxisSize
  4. crossAxisAlignment
  5. verticalDirection
  6. textBaseline

direction#

Sets the direction of the main axis. The values that can be set are Axis.horizontal and Axis.vertical, with the cross axis being perpendicular to the main axis.

mainAxisAlignment:#

Sets the arrangement of child Widgets along the main axis direction, defaulting to MainAxisAlignment.start. The arrangement options are as follows:

  • MainAxisAlignment.start: Left-aligned, default value;
  • MainAxisAlignment.end: Right-aligned;
  • MainAxisAlignment.center: Center-aligned;
  • MainAxisAlignment.spaceBetween: Aligned at both ends;
  • MainAxisAlignment.spaceAround: Equal spacing on both sides of each Widget, with the spacing from the screen edge being half of the spacing between other Widgets;
  • MainAxisAlignment.spaceEvenly: Evenly distributed Widgets, with the spacing from the screen edge equal to the spacing between other Widgets.

The comparison effect is as follows:

image

mainAxisSize#

Sets the size of the main axis, defaulting to MainAxisSize.max. The values that can be set are as follows:

  • MainAxisSize.max: The size of the main axis is the size of the parent container;
  • MainAxisSize.min: The size of the main axis is the sum of the sizes of its child Widgets.

The comparison effect is as follows:

image

When setting mainAxisAlignment to spaceBetween, if mainAxisSize is set to max, it arranges according to spaceBetween based on the entire Row width. If mainAxisSize is set to min, it arranges according to spaceBetween within the sum of the widths of the three Containers.

crossAxisAlignment#

Sets the arrangement of child Widgets along the cross axis direction, defaulting to CrossAxisAlignment.center. The arrangement options are as follows:

  • CrossAxisAlignment.start: Aligned with the starting position of the cross axis;
  • CrossAxisAlignment.end: Aligned with the ending position of the cross axis;
  • CrossAxisAlignment.center: Center-aligned;
  • CrossAxisAlignment.stretch: Fills the entire cross axis;
  • CrossAxisAlignment.baseline: Aligned according to the baseline of the first line of text.

The comparison effect is as follows:

image

verticalDirection#

Sets the arrangement order of child Widgets in the vertical direction, defaulting to VerticalDirection.down. The arrangement options are as follows:

  • VerticalDirection.down: start is at the top, end is at the bottom;
  • VerticalDirection.up: start is at the bottom, end is at the top.

The comparison effect is as follows:

image

Note the changes in the vertical direction based on the cross axis setting of CrossAxisAlignment.end.

textBaseline#

Sets the baseline type for text alignment. The values that can be set are as follows:

  • TextBaseline.alphabetic: Aligned with the alphabetic baseline;
  • TextBaseline.ideographic: Aligned with the ideographic character baseline;

When using, if crossAxisAlignment is set to baseline, the value of the textBaseline property must be set. The usage is as follows:

// textBaseline
class FlexSamplePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Flex Sample"),
        centerTitle: true,
      ),
      body: Row(
        children: <Widget>[
          Expanded(
              child: Row(
                children: <Widget>[
                  Text("躬",style: TextStyle(fontSize: 40,),),
                  Text("x",style: TextStyle(fontSize: 60,),),
                  Text("ing",style: TextStyle(fontSize: 16,),),
                  Text("之",style: TextStyle(fontSize: 16,),),
                ],
          )),
          Expanded(
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.baseline,
                textBaseline: TextBaseline.alphabetic,
                children: <Widget>[
                  Text("躬",style: TextStyle(fontSize: 40,),),
                  Text("x",style: TextStyle(fontSize: 60,),),
                  Text("ing",style: TextStyle(fontSize: 16,),),
                  Text("之",style: TextStyle(fontSize: 16, ),),
                ],
          )),
          Expanded(
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.baseline,
                textBaseline: TextBaseline.ideographic,
                children: <Widget>[
                  Text("躬",style: TextStyle(fontSize: 40, ),),
                  Text("x",style: TextStyle(fontSize: 60,),),
                  Text("ing",style: TextStyle(fontSize: 16,),),
                  Text("之",style: TextStyle(fontSize: 16,),),
                ],
              ))
        ],
      ),
    );
  }
}

The comparison effect for not setting the textBaseline property, setting TextBaseline.alphabetic, and setting TextBaseline.ideographic is as follows:

image

Although the two have different meanings in terms of corresponding baselines, no differences were found in testing. Further observation will continue, and friends who know can comment and point out.

Row and Column#

Row and Column both inherit from Flex. The main axis direction of Row is horizontal, while the main axis direction of Column is vertical, which means that the main axis direction is set based on Flex, as follows:

// Row
direction: Axis.horizontal,
/// Column
direction: Axis.vertical,

If the main axis direction is determined, you can directly use Row or Column, with usage consistent with Flex.

Expanded and Flexible#

The fix property of Flexible defaults to FlexFit.loose, while Expanded inherits from Flexible, with its fix property specified as FlexFit.tight. The two differ because of their different fix properties. If the fit property of Flexible is set to FlexFit.tight, then Flexible is equivalent to Expanded. The fit properties that can be set are as follows:

  • tight: Forces filling the available space;
  • loose: Does not force filling the available space, Widget's own size.

The comparison effect is as follows:

image

Expanded allows components within Row, Column, and Flex to fill the available space along the main axis. If multiple Widgets use the Expanded component, the flex property of Expanded can be used to allocate the main axis space proportionally. The flex property is equivalent to the weight property of Android's LinearLayout, as follows:

// Expanded
class ExpandedSamplePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Row Sample"),
          centerTitle: true,
        ),
        body: Row(
          mainAxisAlignment: MainAxisAlignment.start,
          mainAxisSize: MainAxisSize.max,
          children: <Widget>[
            Expanded(
              flex: 1,
              child: Container(
                  width: 50,
                  height: 50,
                  color: Colors.red,
                  child: Center(
                    child: Text(
                      "A",
                      style: TextStyle(fontSize: 20, color: Colors.white),
                    ),
                  )),
            ),
            Expanded(
              flex: 2,
              child: Container(
                  width: 50, // Width of Row Expanded is ineffective
                  height: 50, // Height of Column Expanded is ineffective
                  color: Colors.green,
                  child: Center(
                    child: Text(
                      "B",
                      style: TextStyle(fontSize: 20, color: Colors.white),
                    ),
                  )),
            ),
            Container(
                width: 50,
                height: 50,
                color: Colors.yellow,
                child: Center(
                  child: Text(
                    "C",
                    style: TextStyle(fontSize: 20, color: Colors.white),
                  ),
                )),
          ],
        ));
  }
}

The display effect is as follows:

image

Spacer#

Spacer is used to adjust the spacing between Widgets and will occupy all remaining space, so the settings of MainAxisAlignment will be ineffective. The flex property of Spacer is used to set the allocation weight of the remaining space, with a default value of 1, indicating that it occupies all remaining space. If there are two or more Spacers, the remaining space is allocated according to flex. The code reference is as follows:

class RowSamplePage1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Row Sample"),
          centerTitle: true,
        ),
        body: ConstrainedBox(
          constraints: BoxConstraints(maxHeight: 150),
          child: Row(
            children: <Widget>[
              Container(
                width: 80,
                height: 80,
                color: Colors.red,
              ),
              Spacer(flex: 1,),
              Container(
                width: 80,
                height: 80,
                color: Colors.green,
              ),
              Spacer(flex: 2,),
              Container(
                width: 80,
                height: 80,
                color: Colors.yellow,
              ),
            ],
          ),
        ));
  }
}

The display effect is as follows:

image

The above mainly covers the content related to the Flex layout in Flutter, focusing on understanding the basic concepts of Flex, and based on this, learning and verifying the Flex layout.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.