layout

Flex layout

The Flex layout in Flutter is similar to the Flex layout in CSS on the Web.

There are Row, Column, Expanded, Flexible, Spacer, Flex controls used to control the Flex layout in Flutter.

Row horizontal layout

The property name type The default value instructions
mainAxisAlignment MainAxisAlignment MainAxisAlignment.start The arrangement of the principal axes
mainAxisSize MainAxisSize MainAxisSize.max The space occupied by the principal axis
crossAxisAlignment CrossAxisAlignment CrossAxisAlignment.center The arrangement of the secondary axes
textDirection TextDirection null Determine the horizontal placement order of children
verticalDirection VerticalDirection VerticalDirection.down Determine the vertical placement order of children
textBaseline TextBaseline null Text reference line alignment

Let’s start by creating three containers of different sizes


class LyoutRowDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Horizontal layout"),
        ),
        body: Container(
          child: Row(
            children: <Widget>[
              Container(
                height: 100,
                width: 50,
                color: Colors.redAccent,
              ),
              Container(
                height: 50,
                width: 50,
                color: Colors.blueAccent,
              ),
              Container(
                color: Colors.black,
                height: 75,
                width: 75() [(), ()). }}Copy the code

Spindle alignment mode MainAxisAlignment

TextDirection and verticalDirection determine the arrangement of the children by these two attributes. Textdirection. LTR is arranged from left to right (using left as the starting position) and TextDirection. RTL is arranged from right to left (using right as the starting position). VerticalDirection Indicates the arrangement in horizontal direction. The starting position is at the top when the value is down. When the value is up, the starting position is at the bottom.

  • Start (the default) sorts the direction according to the textDirection property.

    Place children at the beginning of the spindle

    Figure right with textDirection property value RTL

  • end

    Sort the direction according to the textDirection property.

    Place children at the end of the spindle

    Figure right with textDirection property value RTL

  • center

    Sort the direction according to the textDirection property.

    Place children in the center of the spindle

    Figure right with textDirection property value RTL

  • spaceBetween

    Sort the direction according to the textDirection property.

    Divide the blank areas along the main axis evenly, so that the blank areas between children are equal, and the beginning and the end of the child are close to the beginning and the end, without gaps

    Figure right with textDirection property value RTL

  • spaceAround

    Sort the direction according to the textDirection property.

    The blank areas along the main axis are evenly divided so that the blank areas between children are equal, but the blank areas at the head and tail are half

    Figure right with textDirection property value RTL

  • spaceEvenly

    Sort the direction according to the textDirection property

    The blank areas along the main axis are evenly divided so that the blank areas between children are equal, including the head and tail blank areas

    Figure right with textDirection property value RTL

The arrangement of crossAxisAlignment

MainAxisAlignment mainAxisalign. start is used as an example

  • start

    Aligns the child elements at the starting point on the cross axis. Set verticalDirection to verticaldirection. up

  • end

    Aligns the end of the child elements on the cross axis. Set verticalDirection to verticaldirection. up

  • center

    Center the child elements on the cross axis. Set verticalDirection unchanged.

  • strentch

    Stretch the child elements on the cross axis

  • baseline

    The base line applies to the text for which we first create the text start. Use the baseline. The textBaseline property must be set. Text reference lines for different characters. Mainly alphabetic characters (e.g. English) and ideographic characters (e.g. Chinese) have different reference lines. You must tell Flutter the words you use.

    Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      textBaseline: TextBaseline.alphabetic,
      children: [
        Text(
          'Flutter',
          style: TextStyle(
            color: Colors.yellow,
            fontSize: 30.0
          ),
        ),
        Text(
          'Flutter',
          style: TextStyle(
              color: Colors.blue,
              fontSize: 20.0),),,);Copy the code

Set the alignment mode to baseline

Main axis space mainAxisSize

MainAxisSize has only two values: min and Max. The default is Max.

When the value is min. The spindle shrinks to a minimum.

As shown in figure: even then mainAxisAlignment: for mainAxisAlignment spaceAround. The length of the principal axis is still minimal

Column vertical layout

Vertical layout has the same properties and methods as horizontal layout, the only thing to note is textDirection and verticalDirection

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: "Vertical layout",
        home: Scaffold(
            appBar: AppBar(title: Text("Vertical layout")),
            body: Center(
              child: Column(
			   mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.end,
                children: <Widget>[
                  Text("1",style: TextStyle(fontSize: 100),),
                  Expanded(
                    child: Text("2"),
                  ),
                  Text("33333"),
                  Text("4")],)))); }}Copy the code

Let’s expand 1 just to make it easier to see

Flex layout

We look at the following source code for easy understanding

You can see that Row and Column inherit from Flex.

class Row extends Flex 
class Column extends Flex   
Copy the code

The Row constructor has eight optional named arguments (that is, arguments wrapped around {}).

There are nine super constructors passed to the parent, including direction: Axis. Horizontal.

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>[],
  }) : super(
    children: children,
    key: key,
    direction: Axis.horizontal,
    mainAxisAlignment: mainAxisAlignment,
    mainAxisSize: mainAxisSize,
    crossAxisAlignment: crossAxisAlignment,
    textDirection: textDirection,
    verticalDirection: verticalDirection,
    textBaseline: textBaseline,
  );
}
Copy the code

In Flex, the direction property is actually the direction of the main axis. And marked @required. It’s mandatory.

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>[],
  }) : assert(direction ! =null),
       assert(mainAxisAlignment ! =null),
       assert(mainAxisSize ! =null),
       assert(crossAxisAlignment ! =null),
       assert(verticalDirection ! =null),
       assert(crossAxisAlignment ! = CrossAxisAlignment.baseline || textBaseline ! =null),
       super(key: key, children: children);
Copy the code

Expanded

In the example above we came across a widget that we had never seen before. It’s easy to see. Expanded ignores the size of the child element and forces automatic expansion so that the main axis fills the empty space available to the parent. Expanded must be a child of Row, Column, and Flex.

Here are two examples to make it easier to understand:

// When there is only one child element Expanded
class LyoutExpanded extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Expanded"),
      ),
      body: Center(
        child: Container(
          child: Column(
            children: <Widget>[
              Expanded(
                child: Container(
                  color: Colors.blue,
                  width: 100.// This is ignored),),),),),); }}Copy the code

class LyoutExpanded extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Expanded"),
      ),
      body: Center(
        child: Container(
          height: 50.// The fill makes the spindle expand to the parent height
          child: Column(
            children: <Widget>[
           Expanded(
                child: Container(
                  color: Colors.blue,
                  height: 100.//
                  width: 100,),),),),),),); }}Copy the code

Expanden also has a flex property with a default value of 1. Represents the weights. When the child element has multiple expandens. The height of the parent by weight value (horizontal width when row)

<Widget>[
    Expanded(
        flex: 2,
        child: Container(
            color: Colors.blue,
            width: 100,
        ),
    ),
    Expanded(
        child: Container(
            color: Colors.red,
            width: 100,
        ),
    ),
    Expanded(
        child: Container(
            color: Colors.yellow,
            width: 100,),),,Copy the code

We can see that the blue block is twice as red and twice as yellow.

Flexible

The Flexible component gives Row, Column, Flex and other child components the ability to fill available space in the main axis (for example, Row is horizontal and Column is vertical), but unlike Expanded components, it does not force the child to fill available space. Also the Flexible component must be the children of Row, Column, Flex, and so on.

Flexiible has attribute fit when attribute value flexfit.tight. Flexible and Expanded are no different.

Expanded inheritance and Flexible can be seen from the source code

And the value of fit passed by the parent constructor is flexfit.tight.

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

Passed in the children of Column. Property fit: is flexfit. tight, filling the blank area with weights.

<Widget>[
    Flexible(
        fit: FlexFit.tight,
        child: Container(
            color: Colors.blue,
            height: 100,
            width: 100,
        ),
    ),
    Flexible(
        fit: FlexFit.tight,
        flex: 2,
        child: Container(
            color: Colors.yellow,
            height: 100,
            width: 100,),),,Copy the code

Once the value of fit is flexfit.loose (the default), determine the size of the flex axis, then adjust the height of the element by child. Unforced drawing

For example, the first one forces an extension for Tight. The second is loose and does not force extension.

<Widget>[
    Flexible(
        fit: FlexFit.tight,
        child: Container(
            color: Colors.blue,
            height: 100,
            width: 100,
        ),
    ),
    Flexible(
        fit: FlexFit.loose,
        flex: 2,
        child: Container(
            color: Colors.yellow,
            height: 100,
            width: 100,),),,Copy the code

The height of the yellow Container is 100 because the second one is loose. The fit value of the blue Container is tight, which is the same size as the previous example.

Spacer

Spacer creates a white space that can be adjusted to adjust the spacing between widgets in the Flex container (Row or Colum).

Once children includes Spacer. The attribute value for mainAxisAlignment will not take effect. Spacer has already taken up all the extra space, so there is no space left to reallocate.

Row(
    mainAxisAlignment: MainAxisAlignment.end,// It doesn't work
    children: <Widget>[
        Container(
            height: 100,
            width: 50,
            color: Colors.redAccent,
        ),
        Spacer(),
        Container(
            height: 50,
            width: 50,
            color: Colors.blueAccent,
        ),
        Container(
            color: Colors.black,
            height: 75,
            width: 75,),),Copy the code

Zoom layout

Most of the Flutter widgets are boxes. You can stack them, stack them, nest them.

We can hierarchically nest boxes, but if one box doesn’t fit (the size doesn’t fit) another box. How to solve it?

To solve this problem, Flutter provides a FittedBox, which is similar to the mobile ImageView.

It allows you to fit or align child elements

  • BoxFit. Contain (default) and so on scale up or down, but the content does not exceed the container scope

  • Boxfit. cover scales to fill the container, and the contents may exceed the container range. When the child ratio is different from the container, either the height overflows the container or the width overflows the container.

  • Boxfit.fill does not retain proportional forced stretching (shrinking) to fill containers.

  • Boxfit.fitheight maintains proportions to ensure that the height is displayed completely in the container.

  • Boxfit.fitwidth Maintains the scale to ensure that the width appears intact in the container.

  • Boxfit. none aligns the Child inside the target box (default play) and dismisses the part outside the box. The source file does not zoom in or out.

  • Boxfit. scaleDown aligns the child inside the target box (default). If the child is larger than the container, it contains the same folder. Consistent with None if child is less than the container

To make it easier to understand, let’s take a picture and test it

class Lyoutfitdemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("data")),
      body: Container(
        height: 250,
        width: 250,
        color: Colors.indigo[200],
        child: FittedBox(
          child: Image.asset('images/fittedbox.png')))); }}Copy the code
  1. BoxFit.contain

  1. BoxFit.cover

  1. BoxFit.fill

  1. BoxFit.fitHeight

5.BoxFit.fitWidth

  1. BoxFit.none

  1. BoxFit.scaleDown

Note: Do not create FittedBox, Image contains attribute FIT. The value has the same effect as FittedBox.

Stacked layout

Stack is similar to the Absolute location layout model of the Web. A Stack is not arranged in rows or columns, but in a specific order and position. The position of the Stack can be Positioned using the jam and the Align.

Example: Implement an image gradient effect using a cascading layout

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Gradient status bar",
      home: Scaffold(
        body: Container(
          height: 400,
          child: Stack(
            fit: StackFit.expand,
            children: <Widget>[
              Image.asset(
                'images/Stack.png',
                fit: BoxFit.cover,
              ),
          
              const DecoratedBox(
                decoration: BoxDecoration(
                  gradient: LinearGradient(
                    begin: Alignment(0.0.1.0),
                    end: Alignment(0.0.0.4),
                    colors: <Color>[Color(0x90000000), Color(0x00000000(() (() (() (() (() (() (() (() (() (() (() (() (() (() }}Copy the code

Image gradient effect

This is an example of two controls stacked on top of each other. Of course, children can appear anywhere within the parent. Location control is achieved through two types of widgets.

Align the layout

Align is the alignment component. Set the alignment mode of the child on the parent level, such as container and stack, and adjust the size of the child.

The parent container of this paper is Stack

Alignment

There are several properties

TopLeft, topLeft, topCenter, topRight, centerLeft, center, centerRight, bottomLeft, bottomCenter, bottomRight

class LayoutAlignDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("The align parts"),
        ),
        body: Stack(
          children: <Widget>[
            Align(
              alignment: Alignment.topLeft,
              child: Container(
                width: 100,
                height: 100, color: Colors.red, ), ), ], )); }}Copy the code

Alignment.lerp(Alignment a, Alignment b, double t)

The lERP method takes three parameters. The first two parameters are of an Alignment type and the third parameter is a decimal.

When t is 0, this method returns the value a.

Returns the value of b when t is 1.

When t is 0.5, the widget location is between the positions specified by A and B.

So this t is an offset. Specifies the offset between A and B.

// Add an align to Stack children
Align(
  alignment: Alignment.lerp(Alignment.bottomCenter, Alignment.center,0.5),// Is located in the center of Alignment. BottomCenter and Alignment
  child: Container(
  width: 100,
  height: 100,
  color: Colors.yellow,
   ),
),
Copy the code

Offset alignment

The above describes the offset relative to its modes A and B.

FractionalOffset is another offset method, which is the offset relative to the upper-left corner of the parent component.

Create offset FractionalOffset (dx,dy). Dx and dy are both 0 and 1. The top left position is dx and dy are both 0.

Align(
  alignment: FractionalOffset(0.0.5),
  child: Container(
    width: 100,
    height: 100,
    color: Colors.red,
  ),
),
Copy the code

Also in the source code:

class FractionalOffset extends Alignment
Copy the code

FractionalOffset inherits from Alignment so that all Alignment attributes are available, so we want the widget to be in the upper left and FractionalOffset. TopLeft is also available


class LayoutAlignDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("The align parts"),
        ),
        body: Stack(
          children: <Widget>[
            Align(
              alignment: FractionalOffset(0.0),
              child: Container(
                width: 100,
                height: 100,
                color: Colors.red,
              ),
            ),
            Align(
              alignment: FractionalOffset(0.0.5),
              child: Container(
                width: 100,
                height: 100,
                color: Colors.red,
              ),
            ),
            Align(
              alignment: FractionalOffset(0.1),
              child: Container(
                width: 100,
                height: 100,
                color: Colors.red,
              ),
            ),
            Align(
              alignment: Alignment.lerp(Alignment.bottomCenter, Alignment.center,0.5),
              child: Container(
                width: 100,
                height: 100,
                color: Colors.yellow,
              ),
            ),
            Align(
              alignment: FractionalOffset.topRight,
              child: Container(
                width: 100,
                height: 100, color: Colors.yellow, ), ), ], )); }}Copy the code

Similarly, an Alignment(dx, dy) has the center of the parent container as the origin of the coordinate system. Dx is in the range of -1 to 1, and dy is in the range of -1 to 1. Sets the position of the child element.

Positioned

The Positioned part controls the position of the neutrons in the Stack. 21. The difference between Position and Align is that Position has to be the Children of Stack.

Position has top, bottom, left, right, height, width.

Top, bottom, left, and right are the distances between the boundary of a child element and one of its parent elements.

In other words, when we have a fixed height and a fixed length container, once we determine a quantity left or right and a quantity bottom or top, the position can be determined.

Part of the code

Stack(
    children: <Widget>[
        Positioned(
            top: 100,
            right: 100,
            width: 100,
            height: 100,
            child: Container(
                color: Colors.red,
            ),
        ),
    ],
)
Copy the code

Source code analysis

 const Positioned({
    Key key,
    this.left,
    this.top,
    this.right,
    this.bottom,
    this.width,
    this.height,
    @required Widget child,
  }) : assert(left == null || right == null || width == null),
       assert(top == null || bottom == null || height == null),
       super(key: key, child: child);
Copy the code

If assert(False) throws an error in the horizontal direction

The values in brackets as left = = null | | right = = null | | width = = null

Left, right, width at least one of the values is null this program will not report an error.

That is, left and right can exist together when width is not specified (null). The width of the container is automatically adjusted according to the distance between the edges (left and right).

Stack(
    children: <Widget>[
        Positioned(
            top: 100,
            right: 100,
            left: 100.// width: 100,
            height: 100,
            child: Container(
                color: Colors.red,
            ),
        ),
    ],
)
Copy the code

IndexedStack

IndexedStack inherits from Stack

class IndexedStack extends Stack
Copy the code

It differs from Stack in that it has an index attribute, indicating only the number of elements displayed.

IndexedStack(
    index: 1.// display only the second one
    children: <Widget>[
        Positioned(
            top: 100,
            right: 100,
            left: 100,
            height: 100,
            child: Container(
                color: Colors.red,
            ),
        ),  
        Positioned(
            top: 500,
            right: 100,
            left: 100,
            height: 100,
            child: Container(
                color: Colors.red,
            ),
        ),
    ],
)
Copy the code

The container layout

Container creates a rectangle element. You can decorate it with a BoxDecoration. Background, border, shadow.

class LyoutContainerdemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Container vessel"),
      ),
      body: Container(
        height: 200,
        width: 200,
        child: Text("This is a Container Container"),
        decoration: BoxDecoration(
          color: Colors.red[200].// shape: boxShape. circle, // shape
          border: Border.all(width: 10.0),
          boxShadow: [
            BoxShadow(
              offset: Offset(0.0.100.0), // Fuzzy offset
              color: Color.fromRGBO(16.20.188.1.0), / / color
              blurRadius: 10./ / fuzzy
              spreadRadius: 9.0.// The amount of shadow swell before applying blur[[(), [(), [(), [(); }}Copy the code

To demonstrate the function, this image is exaggerated.

Attach a nice effect

Similar to the Css layout of the box, we can also set the Margin of the box through Margin.

Container(
    margin: EdgeInsets.all(50.0),// The margin is 50.0
    height: 200,
    width: 200,
    decoration: BoxDecoration(
        color: Colors.red[600],
        border: Border.all(width: 2.0),
        boxShadow: [
            BoxShadow(
                offset: Offset(2.0.9.0), / / the offset
                color: Colors.red[200]./ / color
                blurRadius: 10./ / fuzzy
                spreadRadius: 1.0.// The amount of shadow swell before applying blur),,),),Copy the code

Padding layout

Handles the distance between the container and its child elements. The Padding corresponds to the margin property. Margin handles the distance from other components. The effect of the Padding widget and the pading property inside the container is actually the same; when both occur, the actual Padding will be the addition of the two.

class LayoutPaddingDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Padding layout"),
      ),
      body: Container(
        padding: EdgeInsets.all(20.0),//#1 These two properties have the same effect
        decoration: BoxDecoration(
            color: Colors.yellow,
            border: Border.all(color: Colors.white, width: 8.0)),// White border
        child: Padding(
          child: Container(
            decoration: BoxDecoration(
            color: Colors.red,
            border: Border.all(color: Colors.white, width: 8.0)),// White border
          ),
          padding: EdgeInsets.all(10.0),//#1 These two properties have the same effect),),); }}Copy the code

Write in the back

There are more than 30 layout widgets involved in Flutter. There are many ways to achieve the same UI effect. This article focuses on a few commonly used components.

Refer to the link

youtu.be/T4Uehk3_wlY

Medium.com/jlouage/flu…

api.flutter.dev/index.html

flutter.dev/docs