Stack

Flutter 的层叠布局是 Stack,层叠布局允许子 Widget 堆叠(按照代码中声明的顺序),同时子 Widget 可以根据到父容器四个边的位置来确定本身的位置。

Stack 是层叠布局,其子 Widget 会按照添加顺序确定显示层级,后面添加的会覆盖在前面添加的 Widget 上面。

Stack 的快速上手

给 Stack 的 子 Widget 添加内容:

  1. Stack(
  2. children: <Widget>[
  3. Image.asset(
  4. "images/flutter.png",
  5. width: 200,
  6. fit: BoxFit.cover,
  7. ),
  8. Text('Hello Flutter',style: TextStyle(fontSize: 50.0),),
  9. ],
  10. )

Stack 在一个页面使用的完整 Demo 为:

  1. import 'package:flutter/material.dart';
  2. void main() => runApp(StackWidget());
  3. class StackWidget extends StatelessWidget {
  4. @override
  5. Widget build(BuildContext context) {
  6. return MaterialApp(
  7. title: "Flutter Demo",
  8. theme: ThemeData(
  9. primaryColor: Colors.blue,
  10. ),
  11. home: Scaffold(
  12. appBar: AppBar(title: Text("Flutter布局Widget -- 层叠布局")),
  13. body: Stack(
  14. children: <Widget>[
  15. Image.asset(
  16. "images/flutter.png",
  17. width: 200,
  18. fit: BoxFit.cover,
  19. ),
  20. Text('Hello Flutter',style: TextStyle(fontSize: 50.0),),
  21. ],
  22. ),
  23. ),
  24. );
  25. }
  26. }

运行效果为:

Flutter 学习(二十四)层叠布局 - 图1

Stack 的构造函数及参数说明

Stack 的构造函数为:

  1. class Stack extends MultiChildRenderObjectWidget {
  2. Stack({
  3. Key key,
  4. this.alignment = AlignmentDirectional.topStart,
  5. this.textDirection,
  6. this.fit = StackFit.loose,
  7. this.overflow = Overflow.clip,
  8. List<Widget> children = const <Widget>[],
  9. }) : super(key: key, children: children);
  10. ...
  11. }
参数名字 参数类型 意义 必选 or 可选
key Key Widget 的标识 可选
alignment AlignmentDirectional 决定如何对齐 non-positioned 子 Widget 和部分 positioned 子Widget,默认值为 AlignmentDirectional.topStart
部分 positioned 子Widget,在某一个轴上没有定义的,这个轴就使用 alignment 的值,比如 left、right 为横轴,left 和 right 都没有定义,就是横轴没有定义,只要这两个一个有值,这个轴就算有值;top、bottom 为纵轴,同理。
可选
textDirection TextDirection 用于确定 alignment 的对齐方向 可选
fit StackFit 此参数用于决定 non-positioned 子 Widget 如何去适应 Stack 的大小 可选
overflow Overflow 决定如何显示超出 Stack显示空间的子 widget 可选
children List< Widget> Stack 布局里排列的内容 可选

alignment:对齐方式,alignment 的类型是 AlignmentDirectional,注意这里 start 和 end 指的是 textDirection 给定的方向。

AlignmentDirectional 的值 含义
AlignmentDirectional.topStart 上边 start 对齐
AlignmentDirectional.topCenter 上边 居中 对齐
AlignmentDirectional.topEnd 上边 end 对齐
AlignmentDirectional.centerStart 中间 start 对齐
AlignmentDirectional.center 中间 对齐
AlignmentDirectional.centerEnd 中间 end 对齐
AlignmentDirectional.bottomStart 下边 start 对齐
AlignmentDirectional.bottomCenter 下边 居中 对齐
AlignmentDirectional.bottomEnd 下边 end 对齐

Flutter 学习(二十四)层叠布局 - 图2
fit:non-positioned 子 Widget 如何去适应 Stack 的大小,fit 的类型是 StackFit:

StackFit 的值 含义
StackFit.loose 使用子 Widget 自身的大小
StackFit.expand 子 Widget 扩伸到 Stack 的大小
StackFit.passthrough Stack 的 父 Widget 的约束无修改的传递给 Stack 的子 Widget

overflow:如何显示超出 Stack 显示空间的子 widget,overflow 的类型为 Overflow:

Overflow 的值 含义
Overflow.visible 超出部分仍能看见
Overflow.clip 超出部分会被剪裁

Stack 的子 Widget

为了确定子 Widget 到父容器四个角的位置,Stack 将子 Widget 分为两类:

  1. positioned 子 Widget
    positioned 子 Widget 是指被 Positioned 嵌套起来的 Widget,Positioned 可以控制子 Widget 到父容器四个边的距离。
  2. non-positioned 子 Widget
    non-positioned 子 Widget 就是不用 Positioned 嵌套起来的 Widget,non-positioned 子 Widget 使用 Stack 设置的 alignment 来确定自己在父容器里的位置。

Positioned

Positioned 的快速上手

Positioned 在 Stack 里使用的代码 Demo 如下:

  1. import 'package:flutter/material.dart';
  2. void main() => runApp(StackWidget());
  3. class StackWidget extends StatelessWidget {
  4. @override
  5. Widget build(BuildContext context) {
  6. return MaterialApp(
  7. title: "Flutter Demo",
  8. theme: ThemeData(
  9. primaryColor: Colors.blue,
  10. ),
  11. home: Scaffold(
  12. appBar: AppBar(title: Text("Flutter布局Widget -- 层叠布局")),
  13. body: Stack(
  14. fit: StackFit.expand,
  15. children: <Widget>[
  16. Positioned(
  17. left: 50,
  18. top: 100,
  19. child: Image.asset(
  20. "images/flutter.png",
  21. width: 200,
  22. fit: BoxFit.cover,
  23. ),
  24. ),
  25. Text('Hello Flutter'),
  26. ],
  27. ),
  28. ),
  29. );
  30. }
  31. }

运行效果为:

Flutter 学习(二十四)层叠布局 - 图3

Positioned 的构造函数及参数说明

Positioned 的构造函数为:

  1. class Positioned extends ParentDataWidget<Stack> {
  2. const Positioned({
  3. Key key,
  4. this.left,
  5. this.top,
  6. this.right,
  7. this.bottom,
  8. this.width,
  9. this.height,
  10. @required Widget child,
  11. }) : assert(left == null || right == null || width == null),
  12. assert(top == null || bottom == null || height == null),
  13. super(key: key, child: child);
  14. ...
  15. }
参数名字 参数类型 意义 必选 or 可选
key Key Widget 的标识 可选
left double 离 Stack 左边的距离 可选
top double 离 Stack 上边的距离 可选
right double 离 Stack 右边的距离 可选
bottom double 离 Stack 底边的距离 可选
width double 指定 Widget 的宽度 可选
height double 指定 Widget 的高度 可选
children List Stack 布局里排列的内容 可选

注意,此处的 width、height 是用于配合 left、top 、right、 bottom 来定位 Widget 的。举个例子,在水平方向上,你只能指定 left、right、width 三个属性中的两个,如指定 left 和 width 后,right 会自动算出 (left+width),如果同时指定三个属性则会报错,垂直方向同理。

参考

【1】Flutter 实战
【2】Flutter 中文文档
【3】Flutter 完全手册