Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】

文章目录

    • 布局
      • Flex布局
        • row水平布局
          • 主轴排列方式MainAxisAlignment
          • 交叉轴的排列方式crossAxisAlignment
          • 主轴占用的空间mainAxisSize
        • Column垂直布局
        • Flex布局
        • Expanded
        • Flexible
        • Spacer
      • 缩放布局
      • 堆叠布局
        • Align布局
          • Alignment
          • Alignment.lerp(Alignment a, Alignment b, double t)
          • 偏移量对齐
        • Positioned
        • IndexedStack
      • 容器布局
        • Padding布局
      • 写在后面
      • 参考链接

布局

Flex布局

Flutter中的Flex布局和Web的Css类似。

在Flutter 中用于控制Flex布局的有Row,Column,Expanded,Flexible,Spacer,Flex这些控件。

row水平布局

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第1张图片

属性名 类型 默认值 说明
mainAxisAlignment MainAxisAlignment MainAxisAlignment.start 主轴的排列方式
mainAxisSize MainAxisSize MainAxisSize.max 主轴占空间的大小
crossAxisAlignment CrossAxisAlignment CrossAxisAlignment.center 次轴的排列方式
textDirection TextDirection null 确定children在水平方向的摆放顺序
verticalDirection VerticalDirection VerticalDirection.down 确定children在垂直方向的摆放顺序
textBaseline TextBaseline null 文字基准线对齐

我们首先创建三个大小不一的Container


class LyoutRowDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("水平布局"),
        ),
        body: Container(
          child: Row(
            children: [
              Container(
                height: 100,
                width: 50,
                color: Colors.redAccent,
              ),
              Container(
                height: 50,
                width: 50,
                color: Colors.blueAccent,
              ),
              Container(
                color: Colors.black,
                height: 75,
                width: 75,
              )
            ],
          ),
        ));
  }
}

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第2张图片

主轴排列方式MainAxisAlignment

子元素children的排列方式由这两个属性决定textDirection和verticalDirection。textDirection决定水平方向的排列方式TextDirection.ltr从左往右排列(把左当作起始位置),TextDirection.rtl从右往左排列(把右当作起始位置)。verticalDirection时水平方向的排列方式。当值为down(向下排列)时起始位置在顶部。当值为up(向上排列)是起始位置在底部。

  • start (默认值)
    根据textDirection属性排列方向。

    将children放置在主轴的起点

    textDirection属性值为rtl时右图

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第3张图片

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第4张图片

  • end

    根据textDirection属性排列方向。

    将children放置在主轴的末尾

    textDirection属性值为rtl时右图

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第5张图片

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第6张图片

  • center

    根据textDirection属性排列方向。

    将children放置在主轴的中心

    textDirection属性值为rtl时右图

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第7张图片

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第8张图片

  • spaceBetween

    根据textDirection属性排列方向。

    将主轴方向上的空白区域均分,使得children之间的空白区域相等,首尾child都靠近首尾,没有间隙

    textDirection属性值为rtl时右图

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第9张图片

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第10张图片

  • spaceAround

    根据textDirection属性排列方向。

    将主轴方向上的空白区域均分,使得children之间的空白区域相等,但是首尾空白区域为一半

    textDirection属性值为rtl时右图

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第11张图片Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第12张图片

  • spaceEvenly

    根据textDirection属性排列方向

    将主轴方向上的空白区域均分,使得children之间的空白区域相等,包括首尾空白区域

    textDirection属性值为rtl时右图

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第13张图片Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第14张图片

交叉轴的排列方式crossAxisAlignment

都以 mainAxisAlignment: MainAxisAlignment.start为例

  • start

    将子元素在交叉轴上起点对齐。设置verticalDirection为VerticalDirection.up右图。

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第15张图片

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第16张图片

  • end

    将子元素在交叉轴上末尾对齐。设置verticalDirection为VerticalDirection.up右图。

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第17张图片Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第18张图片

  • center

    将子元素在交叉轴上居中对齐。设置verticalDirection无改变。

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第19张图片

  • strentch

    将子元素在交叉轴上拉伸

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第20张图片

  • baseline

    基准线对其适用于文字,我们首先创建文字的start。必须设置textBaseline属性

    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
          ),
        ),
      ],
    );
    

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第21张图片

设置对齐方式为基准线

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第22张图片

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "水平布局",
      home: Scaffold(
          appBar: AppBar(
            title: Text("水平布局"),
          ),
          body: Container(
            child: Row(
              children: [
                Expanded(
                    child: Container(
                  decoration: BoxDecoration(
                    border: Border.all(
                      color: Colors.orange,
                      width: 8.0,
                    ),
                  ),
                  child: Row(
                    children: [
                      Expanded(
                          child: RaisedButton(
                              onPressed: () {},
                              color: Colors.red,
                              child: Container(
                                child: Text(
                                  "红色按",
                                ),
                              ))),
                      Container(
                        width: 50,
                          child: RaisedButton(
                        onPressed: () {},
                        color: Colors.green,
                        child: Text(
                          "绿",
                        ),
                      )),
                      Container(
                        width: 70,
                          child: RaisedButton(
                        onPressed: () {},
                        color: Colors.yellow,
                        child: Text(
                          "黄",
                        ),
                      )),
                    ],
                  ),
                )),
                RaisedButton(
                    onPressed: () {},
                    color: Colors.blue,
                    child: Container(
                      child: Text(
                        "蓝色按钮",
                      ),
                    )),
              ],
            ),
          )),
    );
  }
}

橘黄色框和蓝色按钮占据屏幕整个宽度

红色按钮随意扩展 绿色设置50,黄色设置70

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第23张图片

主轴占用的空间mainAxisSize

mainAxisSize只有两个值一个是min一个是max。默认是max。

当值为min时候。主轴缩紧,变为最小。

如图:即使这时mainAxisAlignment:为MainAxisAlignment.spaceAround。主轴的长度仍为最小状态

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第24张图片

Column垂直布局

垂直布局与水平布局的属性和方法一致,唯一需要注意的是textDirection(水平排列方式)和verticalDirection(垂直排列方式)

import 'package:flutter/material.dart';

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

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

为了便于观看我们将1扩大

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第25张图片

Flex布局

我们查看以下源码便于理解

可以看到RowColumn都继承与Flex

class Row extends Flex 
class Column extends Flex   

Row的构造函数可选命名参数(即{}包裹的参数)有8个。

传入父级的super构造函数却有9个,多出了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 children = const [],
  }) : super(
    children: children,
    key: key,
    direction: Axis.horizontal,
    mainAxisAlignment: mainAxisAlignment,
    mainAxisSize: mainAxisSize,
    crossAxisAlignment: crossAxisAlignment,
    textDirection: textDirection,
    verticalDirection: verticalDirection,
    textBaseline: textBaseline,
  );
}

再Flex中属性direction实际上时主轴的方向。且被@required标注。它是必选的。

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 children = const [],
  }) : 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);

Expanded

上面的例子我们遇到从未见过的一个widget。很容易就可以看出。Expanded会忽略子元素的大小并强制自动扩展使主轴填充父级可用的空白区域。Expanded必须是Row、Column、Flex的children。

下面两个例子便于更好理解:

//当子元素只有一个Expanded时
class LyoutExpanded extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Expanded"),
      ),
      body: Center(
        child: Container(
          child: Column(
            children: [
              Expanded(
                child: Container(
                  color: Colors.blue,
                  width: 100,//这个被忽略掉了
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第26张图片

class LyoutExpanded extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Expanded"),
      ),
      body: Center(
        child: Container(
          height: 50,//填充使主轴扩展至父级高度
          child: Column(
            children: [
           Expanded(
                child: Container(
                  color: Colors.blue,
                  height: 100,//
                  width: 100,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第27张图片

Expanden还有一个属性为flex默认值为1。代表权重。当子元素有多个Expanden。按照权重值占据父级的高度(row时为水平宽度)

[
    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,
        ),
    ),
],

我们可以看到蓝色的块时红和黄的二倍。

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第28张图片

Flexible

Flexible组件可以使Row、Column、Flex等子组件在主轴方向有填充可用空间的能力(例如,Row在水平方向,Column在垂直方向),但是它与Expanded组件不同,它不强制子组件填充可用空间。同样Flexible组件必须是Row、Column、Flex等组件的children。

Flexiible 有属性fit当属性值FlexFit.tight时。Flexible和Expanded没有区别。

从源码可以看出Expanded继承与Flexible

且引用 上级构造函数传入fit的值为FlexFit.tight。

class Expanded extends Flexible
//省区其他源码
    

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

在Column的children中传入。属性fit:为FlexFit.tight,按照权值填充空白区域。

[
    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,
        ),
    ),
],

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第29张图片

一旦fit的值为FlexFit.loose(默认值)先按flex的值分主轴确定占主轴的大小,再按child调整元素的高度。不强制拉伸

例如第一个为tight强制扩展。第二个为loose不强制扩展。

[
    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,
        ),
    ),
],

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第30张图片

因为第二个为loose所以黄颜色的Container高度为100。而蓝色Container的 fit值为 tight,他的大小和上一个例子一致。

Spacer

Spacer创建一个可以调整的空白区域,可用于调整Flex容器(Row或者Colum)中widget之间的间距。

一旦children里面包含了Spacer。mainAxisAlignment的属性值将起不到作用。Spacer已经占据了所有额外的空间,因此没有剩余的空间可以重新分配。

Row(
    mainAxisAlignment: MainAxisAlignment.end,//起不到作用
    children: [
        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,
        )
    ],
),

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第31张图片

缩放布局

绝大多数flutter的widget是盒子。可以将他们叠放,堆叠,嵌套。

我们可以层级嵌套盒子,但是如果一个盒子不适合(大小不适合)另一个盒子。该如何解决?

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第32张图片

为了解决这个问题Flutter提供了FittedBox,这个和移动端的ImageView类似。

它实现的功能是使子元素缩放(fit)或者调整位置(alignment)

  • BoxFit.contain(默认值)等比例扩大或缩小,但内容不会超过容器范围

  • BoxFit.cover按照比例逐步扩大至充满容器,内容有能会超过容器范围。当child比例与容器不同时,要么高度溢出容器,要么宽度溢出容器。

  • BoxFit.fill不保留比例强制拉伸(缩小)填充容器。

  • BoxFit.fitHeight保持比例确保高度在容器中显示完整。

  • BoxFit.fitWidth保持比例确保宽度在容器中显示完整。

  • BoxFit.none将child对齐在目标框内(默认剧中),并丢弃位于框外的部分,源文件不放大也不缩小。

  • BoxFit.scaleDown将child对齐在目标框内(默认剧中),当child大于容器,则与contain一致。如果child小于容器,则与none一致

为了便于理解我们可以找一个图片进行测试

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')),
      ),
    );
  }
}
  1. BoxFit.contain

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第33张图片

  1. BoxFit.cover

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第34张图片

  1. BoxFit.fill

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第35张图片

  1. BoxFit.fitHeight

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第36张图片

5.BoxFit.fitWidth

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第37张图片

  1. BoxFit.none

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第38张图片

  1. BoxFit.scaleDown

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第39张图片
Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第40张图片

备注:不用创建FittedBox,Image含有属性fit。值效果和FittedBox一致。

堆叠布局

Stack不是Row或者Colum定位的,而是按照特定顺序堆叠。可以使用 Positioned作为Stack的wiget来定位。Stack与web绝对定位布局模型类似。

示例:可以使用层叠布局实现一个 图片渐变效果

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "渐变状态栏",
      home: Scaffold(
        body: Container(
          height: 400,
          child: Stack(
            fit: StackFit.expand,
            children: [
              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(0x90000000), Color(0x00000000)],
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

图片渐变效果

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第41张图片

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第42张图片

这是两个控件堆叠在一起的例子。当然children也可以出现在任何位置。可以通过两个widget控制。

Align布局

Align为对齐部件,设置child的在父级的(如container、stack等)对齐方式,并根据child的尺寸调整自身的尺寸。

本文的父级容器选用stack

Alignment

其中有这几种属性

topLeft(左上),topCenter(顶部中央),topRight(右上),centerLeft,center,centerRight,bottomLeft,bottomCenter,bottomRight

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

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第43张图片

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

lerp方法有三个参数,前两个参数为Alignment类型,第三个参数为小数。

当t为0时,这个方法返回的值为a。

当t为1时,返回b的值。

当t为0.5时,这个widget位置就位于a和b指定的位置中间。

所以这个t为一个偏移量。指定为a到b之间的偏移。

//在Stack children中添加一个align
Align(
  alignment: Alignment.lerp(Alignment.bottomCenter, Alignment.center,0.5),//位于Alignment.bottomCenter和Alignment.center的中央
  child: Container(
  width: 100,
  height: 100,
  color: Colors.yellow,
   ),
),

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第44张图片

偏移量对齐

上面介绍了相对于对其方式a和b的偏移对其。

FractionalOffset 是另外一个偏移方法,它是相对于父部件左上角的偏移。

创建偏移量FractionalOffset (dx,dy)。dx和dy的取值都是0~1。左上的位置为dx和dy都为0。

Align(
  alignment: FractionalOffset(0, 0.5),
  child: Container(
    width: 100,
    height: 100,
    color: Colors.red,
  ),
),

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第45张图片

另外在源码中:

class FractionalOffset extends Alignment

FractionalOffset继承于Alignment所以Alignment的属性都可以使用,这样我们要使得widget位于左上也可以用使用FractionalOffset.topLeft


class LayoutAlignDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("align部件"),
        ),
        body: Stack(
          children: [
            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,
              ),
            ),
          ],
        ));
  }
}

与之相类似的还有Alignment(dx, dy),以父级容器的中心为坐标系原点。dx的取值范围为-11,dy的取值范围为-11。设置子元素的位置。

Positioned

Positioned 部件可以控制Stack中子元素的位置。Positioned 与Align不同的是Position必须是Stack的Children。

Position有topbottomleftrightheightwidth

topbottomleftright这些量都是与某一边界的距离。

当一个大小高度和长度固定容器一旦我们确定其水平方向和垂直方向上各一个量。其位置是固定的。

部分代码

Stack(
    children: [
        Positioned(
            top: 100,
            right: 100,
            width: 100,
            height: 100,
            child: Container(
                color: Colors.red,
            ),
        ),
    ],
)

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第46张图片

源码分析

 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);

在水平方向上如果assert(false)会抛出错误

而括号里的值为left == null || right == null || width == null

left ,right ,width 至少有一个值为null这个程序才不会报错。

也就是说当width未指定(为空)使left和right是可以同时存在的。这时的容器的宽度会以据边界的距离(left和right)自动调整。

Stack(
    children: [
        Positioned(
            top: 100,
            right: 100,
            left: 100,
            // width: 100,
            height: 100,
            child: Container(
                color: Colors.red,
            ),
        ),
    ],
)

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第47张图片

IndexedStack

IndexedStack继承于Stack

class IndexedStack extends Stack

他和Stack不同的是有一个index的属性,表示只显示第几个元素。

IndexedStack(
    index: 1,//只显示第二个
    children: [
        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,
            ),
        ),
    ],
)

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第48张图片

容器布局

Container可以创建一个矩形元素。可以用BoxDecoration进行装饰。背景,边框,阴影。

class LyoutContainerdemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Container容器"),
      ),
      body: Container(
        height: 200,
        width: 200,
        child: Text("这是一个Container容器"),
        decoration: BoxDecoration(
          color: Colors.red[200],
          // shape: BoxShape.circle, //形状
          border: Border.all(width: 10.0),
          boxShadow: [
            BoxShadow(
              offset: Offset(0.0, 100.0), //模糊偏移量
              color: Color.fromRGBO(16, 20, 188, 1.0), //颜色
              blurRadius: 10, //模糊
              spreadRadius: -9.0, //在应用模糊之前阴影的膨胀量
            ),
          ],
        ),
      ),
    );
  }
}

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第49张图片

为了演示功能,这个图片效果做的比较夸张。

附上一个好看的效果

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第50张图片

相似于Css的盒子布局,我们也可以通过Margin给盒子设置外边距。

Container(
    margin: EdgeInsets.all(50.0),//外边距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), //偏移量
                color: Colors.red[200], //颜色
                blurRadius: 10, //模糊
                spreadRadius: -1.0, //在应用模糊之前阴影的膨胀量
            ),
        ],
    ),
),

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第51张图片

Padding布局

用于处理容器与子元素之间的距离。与Padding对应的是margin属性。margin用于处理与其他组件之间的距离。Padding部件和容器内的pading属性的效果实际上是一致的,当同时出现,真实的padding将是两者相加。

class LayoutPaddingDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Padding 布局"),
      ),
      body: Container(
        padding: EdgeInsets.all(20.0),//#1这两处的属性效果是一致的
        decoration: BoxDecoration(
            color: Colors.yellow,
            border: Border.all(color: Colors.white, width: 8.0)),//白色边框
        child: Padding(
          child: Container(
            decoration: BoxDecoration(
            color: Colors.red,
            border: Border.all(color: Colors.white, width: 8.0)),//白色边框
          ),
          padding: EdgeInsets.all(10.0),//#1这两处的属性效果是一致的
        ),
      ),
    );
  }
}

Flutter布局——Flex、FittedBox、Stack、Container布局教程【超详细】_第52张图片

写在后面

Flutter中涉及到布局的Widget有30多种,一样的效果的ui,实现的途径有很多中。本篇就重点涉及几个常用的部件。

参考链接

https://youtu.be/T4Uehk3_wlY

https://medium.com/jlouage/flutter-row-column-cheat-sheet-78c38d242041

https://api.flutter.dev/index.html

https://flutter.dev/docs

你可能感兴趣的:(Flutter)