• The layout Widget for Flutter
  • Related blog series: The Flutter and Dart series
  • relatedDemoAddress:Making the address
  • Layout of the classWidgetWill contain one or more childrenwidget, different layout classesWidgetpairswidgetLayout (layout) in different ways
  • Previous articleMentioned:WidgetIn factElementConfiguration data ofWidgetThe function is to describe aUIElement of a configuration data, while trueUIApply colours to a drawing is made up ofElementConstitute a
  • inFlutterAccording toWidgetWhether the child nodes need to be included willWidgetIt’s divided into three categories, corresponding to three categoriesElementThe following table,
Widget The corresponding Element use
LeafRenderObjectWidget LeafRenderObjectElement WidgetThe leaf node of a tree, used when there are no childrenwidget, usually basiswidgetAll fall into this category, e.gText,Image
SingleChildRenderObjectWidget SingleChildRenderObjectElement Contains one childWidget, such as:ConstrainedBox,DecoratedBoxEtc.
MultiChildRenderObjectWidget MultiChildRenderObjectElement Contains more than one childWidgetThere is usually onechildrenParameter, accept oneWidgetThe array. Such asRow,Column,StackEtc.

The Widget layout class

  • Layout of the classWidgetIt means direct or indirect inheritance.MultiChildRenderObjectWidgettheWidgetThey usually have onechildrenProperty is used to receive the childWidget
  • WidgetIs as follows:
    • Widget > RenderObjectWidget > (Leaf/SingleChild/MultiChild)RenderObjectWidget
  • RenderObjectWidgetClass defines create, updateRenderObjectMethods that subclasses must implement them
  • For the layout classWidgetIn terms of its layout algorithms are all through the correspondingRenderObjectObject
  • FlutterThere are mainly the following types of layout classesWidget:
    • Linear layoutRowandColumn
    • Elastic layoutFlex
    • Fluid layoutWrap,Flow
    • Cascade layoutStack,Positioned

Linear layout

  • RowandColumnIt’s a current layoutWidgetAre inherited fromFlex
  • A linear layout is a horizontal or vertical layoutThe child widgets
  • For a linear layout, there is a main axis and a vertical axis. If the layout is horizontal, then the main axis is the horizontal direction and the vertical axis is the vertical direction. If the layout is vertical, then the main axis is vertical and the vertical axis is horizontal
  • RowThe principal axis of is the horizontal direction,ColumnThe main axis of the vertical direction, cut both attributes and use are the same
  • The source code defined below is as follows:
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>[],
})

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

The related attributes are as follows

mainAxisAlignment

The arrangement of child widgets in the main axis is referred to as a component for convenience

/ / the default value
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start
Copy the code
  • startSon:widgetsI’m going to go to the starting point of the principal axis
  • endSon:widgetsI’m going to go to the end of the principal axis
  • center: all of the childrenwidgetsCentered alignment
  • spaceBetween: Evenly distributed, adjacentwidgetsThe distance is the same. The first one in each rowwidgetsAlign with the beginning of the line, last on each linewidgetsAlign with the end of the line
  • spaceAround: Evenly distributed, adjacentwidgetsThe distance is the same. The first one in each rowwidgetsThe distance to the beginning of the line and the last one in each linewidgetsThe distance to the end of the line will be adjacentwidgetsHalf the distance between
  • spaceEvenly: Evenly distributed, adjacentwidgetsThe distance is the same. The first one in each rowwidgetsThe distance to the beginning of the line and the last one in each linewidgetsDistance to the end of the line and adjacencywidgetsThe same distance between
attribute The effect
start
end
center
spaceBetween
spaceAround
spaceEvenly

mainAxisSize

/ / the default value
MainAxisSize mainAxisSize = MainAxisSize.max
Copy the code
  • saidRowSpace taken up in the main axis (horizontal) direction, default isMainAxisSize.max
  • maxRepresents as much horizontal space as possible, at this time regardless of the childwidgetsHow much horizontal space is actually occupied,RowThe width of is always equal to the maximum width in the horizontal direction;
  • MainAxisSize.minMeans to occupy as little horizontal space as possible, whenwidgetsDoes not occupy the horizontal remaining space, thenRowThe actual width of is equal to all of the childrenwidgetsThe horizontal space occupied

verticalDirection

Indicates the alignment of the vertical axis of the Row. The default value is down, indicating that the Row is from top to bottom. Up means from the bottom up

/ / the default value
VerticalDirection verticalDirection = VerticalDirection.down
Copy the code

crossAxisAlignment

  • Said the childWidgetsThe alignment in the vertical direction,RowThe height of PI is equal to PIWidgetsThe height of the highest child element in
  • crossAxisAlignmentThe reference frame of isverticalDirection
/ / the default value
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center

/** ** Verticaldirection. down crossAxisAlignment. Start Crossaxisalignment. start refers to bottom alignment * crosSAXisalignment. end and crosSAXisalignment. start are opposite */
Copy the code
  • whenVerticalDirection.downWhen,crossAxisAlignmentThe enumerated values are as follows
  • start: top to it
  • end: Bottom to it
  • center: Center against it
  • stretch: on the side axis, the childWidgetThe height of phi is stretched to phiRowIs the same height
  • baseline: no matterVerticalDirectionWhat is the value, sonWidgetThe top andRowThe top of it

textDirection

Indicates the horizontal layout order of the child widgets (left to right or right to left). The default is the text orientation of the system’s current Locale (for example, left to right for Chinese and English, but right to left for Arabic).

TextDirection textDirection
/** * LTR: left to right * RTL: right to left */
Copy the code

textBaseline

Use the horizontal line on its text, see for details

TextBaseline textBaseline
/** * Alphabetic: used to align common alphabetic baselines ** ideographic: used to align ideographic baselines */
Copy the code

Use the code

    Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.center,
        textDirection: TextDirection.ltr,
        verticalDirection: VerticalDirection.down,
        textBaseline: TextBaseline.ideographic,
        children: <Widget>[
          new Container(width: 80.0, height:80.0, color: Colors.red,),
          new Container(width: 80.0, height:90.0, color: Colors.green,),
          new Container(width: 80.0, height:100.0, color: Colors.blue,),
        ],
    )
Copy the code

Pay special attention to

In Row and Column, an overflow error is reported if the child widget is out of screen range

Elastic layout

  • Elastic layout allows childrenwidgetThe parent container space is allocated proportionally
  • FlutterThe elastic layout is mainly throughFlexandExpandedTo coordinate the implementation
  • FlexChildren can be arranged horizontally or verticallywidget
  • If the spindle direction is known, use itRoworColumnBecause theRowandColumnAll inherit fromFlex, parameters are basically the same, so it can be usedFlexThe place must be usableRoworColumn
  • FlexIt’s powerful on its own, and it can work withExpandedWith elastic layout, we will discuss onlyFlexProperties related to elastic layout (other properties have already been introducedRowandColumnWas introduced at the time.)

Flex

Flex({
    Key key,
    // The direction of the elastic layout
    @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>[],
})

// direction
// Horizontal direction
Axis direction = Axis.horizontal
// Vertical direction, default vertical direction
Axis direction = Axis.vertical
Copy the code

Flex inherits from MultiChildRenderObjectWidget, corresponding RenderObject RenderFlex, RenderFlex implemented in its layout algorithm

Expanded

You can scale the space taken up by Row, Column, and Flex child widgets

class Expanded extends Flexible {
  
  const Expanded({
    Key key,
    int flex = 1.@required Widget child,
  }) : super(key: key, flex: flex, fit: FlexFit.tight, child: child);
}
Copy the code

Flex is the elastic coefficient. If it is 0 or NULL, child is inelastic, that is, the space not occupied by expansion. If greater than 0, all Expanded partitions the total free space of the spindle in proportion to their Flex

    Row(
        children: <Widget>[
          Container(width: 80.0, height:80.0, color: Colors.red,),
          Expanded(
            flex: 1,
            child: Container(width: 80.0, height:80.0, color: Colors.blue,),
          ),
          Expanded(
            flex: 1,
            child: Container(width: 80.0, height:80.0, color: Colors.yellow,),
          )
        ],
      ),
Copy the code

Fluid layout

  • It was mentioned above thatRowandColumnIn, if the sonwidgetOut of screen range, an overflow error is reported
  • This is becauseRowThere is only one line by default and no line folding if it goes beyond the screen
  • We call the layout that folds automatically when you go beyond the screen a streaming layout
  • FlutterThrough theWrapandFlowTo support streaming layouts

Wrap

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

You can see that many of the properties in Wrap are the same as those in Row, so instead of going over them here, we’ll focus on the properties that are unique to Wrap

alignment

The way the child widgets are on the main axis

/ / the default value
this.alignment = WrapAlignment.start
// Values: start, end, center, spaceBetween, spaceAround, spaceinstituted
Copy the code

runAlignment

Child widgets on the vertical axis on their way

/ / the default value
this.runAlignment = WrapAlignment.start
// Values: start, end, center, spaceBetween, spaceAround, spaceinstituted
Copy the code

spacing

Spacing of sub-widgets in the spindle direction: spacing: 10

runSpacing

Spacing of child widgets in the vertical axis: runSpacing: 10

Flow

  • It’s rarely usedFlowBecause it is too complex, you need to implement it yourselfwidgetIn many scenarios, the first thing to consider isWrapWhether the requirements are met
  • FlowIt is mainly used in UI that requires custom layout or in scenes that require high performance (such as animation)
  • FlowIt has the following advantages:
    • Good performance:FlowIs a rightchildVery efficient controls for size and position adjustment,FlowUse transformation matrix pairschildOptimizations were made when the position was adjusted
    • inFlowAfter positioning, ifchildHas changed in size or position inFlowDelegateIn thepaintChildren()Method callcontext.paintChildI’m going to redraw, andcontext.paintChildThe transformation matrix was used in the redraw without actual adjustmentWidgetPosition.
    • Flexibility: Because we need to implement it ourselvesFlowDelegatethepaintChildren()Method, so we need to calculate each one ourselveswidgetThe location, therefore, can be implemented custom layout.
  • Disadvantages:
    • Complex to use.
    • Can’t adaptwidgetSize, must be specified by the parent container size or overriddenFlowDelegatethegetSizeReturn fixed size
  • Here is a simple example code:
class FlowWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
      color: Colors.orange,
      child: Flow(
        delegate: ShowFlowDelegate(margin: EdgeInsets.all(10)),
        children: <Widget>[
          Container(width: 100.0, height:100.0, color: Colors.red),
          Container(width: 100.0, height:100.0, color: Colors.yellow),
          Container(width: 100.0, height:100.0, color: Colors.blue),
          Container(width: 100.0, height:100.0, color: Colors.cyan),
          Container(width: 100.0, height:100.0, color: Colors.pink) ], ), ); }}Copy the code

Implement a class that inherits from FlowDelegate and overwrites the response method

class ShowFlowDelegate extends FlowDelegate {
  EdgeInsets margin =EdgeInsets.zero;
  ShowFlowDelegate({this.margin});

  @override
  void paintChildren(FlowPaintingContext context) {
    var x = margin.left;
    var y = margin.top;
    // Calculates the position of each child widget
    for (int i = 0; i < context.childCount; i++) {
      var w = context.getChildSize(i).width + x + margin.right;
      if (w < context.size.width) {
        context.paintChild(i,
            transform: new Matrix4.translationValues(
                x, y, 0.0));
        x = w + margin.left;
      } else {
        x = margin.left;
        y += context.getChildSize(i).height + margin.top + margin.bottom;
        // Draw child widgets (optimized)
        context.paintChild(i,
            transform: new Matrix4.translationValues(
                x, y, 0.0)); x += context.getChildSize(i).width + margin.left + margin.right; }}}@override
  Size getSize(BoxConstraints constraints) {
    // Set the Flow size
    return Size(double.infinity, 300);
  }

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

Cascade layout

  • Cascading layout andWebAbsolute positioning,iOSIn theFrameThe layout is similar to the subwidgetIts position can be determined by the position of the four corners to the parent container
  • Absolute positioning permitwidgetStack (in the order declared in the code)
  • FlutterThe use ofStackandPositionedTo achieve absolute positioning,StackAllow the childwidgetStack,PositionedCan give a childwidgetpositioning

Stack

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

Determines the position of the child widgets in the Stack

/ / the default value
this.alignment = AlignmentDirectional.topStart

// Start and end are horizontal directions, and top and bottom are vertical directions
static const AlignmentDirectional topStart = AlignmentDirectional(1.0.1.0);
static const AlignmentDirectional topCenter = AlignmentDirectional(0.0.1.0);
static const AlignmentDirectional topEnd = AlignmentDirectional(1.0.1.0);

static const AlignmentDirectional centerStart = AlignmentDirectional(1.0.0.0);
static const AlignmentDirectional center = AlignmentDirectional(0.0.0.0);
static const AlignmentDirectional centerEnd = AlignmentDirectional(1.0.0.0);

static const AlignmentDirectional bottomStart = AlignmentDirectional(1.0.1.0);
static const AlignmentDirectional bottomCenter = AlignmentDirectional(0.0.1.0);
static const AlignmentDirectional bottomEnd = AlignmentDirectional(1.0.1.0);

// You can also use specific numerical scale positioning, set the value between 0 and 1
AlignmentDirectional(0.8.0.9)
Copy the code

textDirection

Determines the reference frame of alignment

/ / LTR by default
textDirection: TextDirection.ltr

LTR; // textDirection is textdirection. LTR
// The textDirection value is textDirection. RTL. The alignment start indicates the right and end indicates the left
Copy the code

fit

How do unpositioned child widgets fit into the Stack size

/ / the default value
this.fit = StackFit.loose

// stackfit.loose indicates the size to use the child widgets
// StackFit. Expand specifies the size to expand to the Stack
Copy the code

overflow

Decide how to display child widgets that exceed the Stack display space

/ / the default value
this.overflow = Overflow.clip

// Overflow. clipped (hidden)
// overflow. visible will not be clipped
Copy the code

Use the sample

Stack(
  // alignment: AlignmentDirectional.center,
  alignment: AlignmentDirectional(0.8.0.8),
  textDirection: TextDirection.ltr,
  fit: StackFit.loose,
  overflow: Overflow.visible,
  children: <Widget>[
    Container(width: 100.0, height:100.0, color: Colors.red),
    Container(width: 100.0, height:100.0, color: Colors.yellow),
  ],
)
Copy the code

Positioned

The position and size of the Frame in tourists and iOS are the same, positioning and size of the Widget is set according to the upper, lower, left and right and the width and height

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

Left, top, right, and bottom represent the distances from the left, top, right, and bottom sides of the Stack, respectively. Width and height specify the width and height of the positioning element

Note that width and height here have slightly different meanings than elsewhere. This is used to position widgets with the left, top, right, and bottom attributes. For example, in the horizontal direction, you can specify only two of the left, right, and width attributes. If left and width are specified, right is automatically calculated (left+width). If three attributes are specified at the same time, an error is reported

child: Stack(
  alignment: AlignmentDirectional.center,
  children: <Widget>[
    // The widget is displayed according to the alignment Settings
    Container(child: Text('https', style: TextStyle(color: Colors.red)), color: Colors.yellow,),
    // The widget displays independent alignment based on the left and top and width Settings. The actual width is 80
    Positioned(
      left: 10,
      top: 30,
      width: 80,
      child: Container(width: 100.0, height:100.0, color: Colors.red),
    ),
    Positioned(
      right: 10,
      bottom: 50,
      child: Container(width: 100.0, height:100.0, color: Colors.blue),
    )
  ],
),
Copy the code

At this point, all the layout related widgets in Flutter have been learned…… Next comes the container class Widget

reference

  • Flutter of actual combat
  • Because Chinese website

Please scan the following wechat official account and subscribe to my blog!