一、Stack Widget 和 Align Widget 实现绝对定位

1、Stack Widget

HTML 中实现绝对定位使用的 absolute 属性,native 中所有的一切都是绝对定位

在 Flutter 中封装了非常方便的 Widget 来进行绝对定位

Stack Widget 是定位发生的容器,只有在 Stack 中,绝对定位的 Widget 才会生效

Stack 的构造方法非常简单:

  /// Creates a stack layout widget.
  ///
  /// By default, the non-positioned children of the stack are aligned by their
  /// top left corners.
  Stack({
    Key key,
    this.alignment = AlignmentDirectional.topStart,
    this.textDirection,
    this.fit = StackFit.loose,
    this.overflow = Overflow.clip,
    List<Widget> children = const <Widget>[],
  }) : super(key: key, children: children);

其中关键的属性就是 children,除了几个样式控制的参数之外,通过 children 可以传入一个 Widget 列表,用于表用在 Stack 中进行绝对定位的 Widget

2、Align Widget

Align 是一个 具有 Alignment 属性的 Widget,基础的属性就是 alignment,并且默认值是 Aligment.center

构造函数如下:

  const Align({
    Key key,
    this.alignment = Alignment.center,
    this.widthFactor,
    this.heightFactor,
    Widget child,
  }) : assert(alignment != null),
       assert(widthFactor == null || widthFactor >= 0.0),
       assert(heightFactor == null || heightFactor >= 0.0),
       super(key: key, child: child);

除了可以指定 aligment 之外,还可以传入一个 Widget 作为 子 widget

3、Stack + Align 实现的绝对定位

Align 的构造可以看出,通过 Stack + Align 实现的绝对定位可选择的位置是比较少的

        Stack(
          children: <Widget>[
            Align(
              child: Icon(Icons.home, size: 40, color: Colors.white),
              alignment: Alignment.topCenter,
            ),
            Align(
              child: Icon(Icons.search, size: 40, color: Colors.pink),
              alignment: Alignment.bottomLeft,
            ),
            Icon(Icons.settings, size: 40, color: Colors.blue),
            Icon(Icons.arrow_drop_down, size: 40, color: Colors.red),
          ],
          alignment: Alignment.center,
        )

上面代码中,前两个 Widget 我是使用的 Align Widget,并且分别指定了 aligment 的属性时 topCenterbottomLeft

而下面的两个 Icon,则是普通的 Widget,没有使用 Aligment

最终效果:

32666-f8f2yww8zk.png

可以发现,如果在 Stack 中不指定 Align 这种 Widget,最终的都会在 Stack 指定的 aligment 属性位置布局(示例中我设置了基于中间进行布局),而且会重叠在一起,这也和 absolute 的属性比较相似

二、Positioned Widget

相比于 Align Widget 布局的局限性(只能指定 Aligment 的几个属性),Positioned Widget 在绝对布局上更加 贴合 absolute 的方式

Positioned 提供了 left、top、right、bottom 四个属性来进行布局定位,构造方法如下:

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

Stack + Postioned 进行绝对定位布局的示例:

        Stack(
          children: <Widget>[
            Positioned(
                child: Icon(Icons.home, size: 40, color: Colors.white),
                left: 0,
                top: 0),
            Positioned(
                child: Icon(Icons.search, size: 40, color: Colors.pink),
                left: 0.4),
            Positioned(
                child: Icon(Icons.settings, size: 40, color: Colors.blue),
                bottom: 1),
          ],
          alignment: Alignment.center,
        )

最终效果:

50871-2hwa5fz3p2g.png

上面的结果中,第一个图片 home 坐标是 top: 0, left:0

search 图标使用的是 left:0.4

settings 图标使用的是 bottom: 1

如果使用 bottom:1, left: 1 的图标的效果是:

Positioned(
                child: Icon(Icons.settings, size: 40, color: Colors.blue),
                bottom: 1, left: 1),

45169-qoyfsktugf.png

Positioned(
                child: Icon(Icons.settings, size: 40, color: Colors.blue),
                bottom: 1, right: 1),

12628-ajqs2s11pck.png

Positioned(
                child: Icon(Icons.settings, size: 40, color: Colors.blue),
                top: 0.5, right: 0.5),

18551-w901cjj1cgm.png

Positioned(
                child: Icon(Icons.settings, size: 40, color: Colors.blue),
                top: 0.5, right: 0.1),
Positioned(
                child: Icon(Icons.settings, size: 40, color: Colors.blue),
                top: 0),

08911-v6l0ecuzh8c.png

三、完整代码

1、Stack + Aligment

https://github.com/postbird/FlutterHelloWorldDemo/blob/master/demo1/lib/bak/main.19-Stack%20Align%20%E7%BB%84%E4%BB%B6.dart

2、Stack + Positioned

https://github.com/postbird/FlutterHelloWorldDemo/blob/master/demo1/lib/bak/main.20-Stack%20Positioned.dart