层叠布局和Web中的绝对定位,以及iOS中的Frame布局是相似的,子部件可以根据距离父部件资格角的位置来确定自身的位置;其允许子部件按照代码中声明(添加)的顺序堆叠起来。

通常情况下,在Flutter中我们使用StackPositioned两个部件组合使用来实现绝对定位。Stack来实现足部件堆叠起来,而Positioned用来根据Stack的四个角来确定子部件的具体位置;

Stack

Flutter中,Stack定义如下:

  1. Stack({
  2. Key? key,
  3. this.alignment = AlignmentDirectional.topStart,
  4. this.textDirection,
  5. this.fit = StackFit.loose,
  6. this.overflow = Overflow.clip,
  7. this.clipBehavior = Clip.hardEdge,
  8. List<Widget> children = const <Widget>[],
  9. })
  • alignment:此参数表示如果我们没有定位子部件或者子部件只进行了部分定位时的对齐方式;
    • 没有定位:没有使用Positioned进行定位;
    • 部分定位:特指没有在某一个轴上定位:
      • leftright为横轴;topbottom为纵轴;只要包含某个轴上的一个定位属性,那么就算在该轴上有定位
  • textDirection:和RowtextDirection功能一样,都用于确定alignment对齐时的参考系;
    • textDirection值为TextDirection.ltr,则alignmentstart表示左边,end表示右边;也就是从左到右的顺序;
    • textDirection值为TextDirection.rtl,则alignmentstart表示右边,end表示左边;也就是从右到左的顺序;
  • fix:用来确定没有定位的子部件如何适应Stack的大小;
    • StackFit.loose:使用子部件的大小;
    • StackFit.expand:拉伸到Stack的大小;
  • overflow:用来决定如何显示超出了Stack显示区域的子部件;

    • Overflow.clip:子部件超出Stack显示区域的那部分会被裁剪,或者说隐藏;
    • Overflow.visible:超出显示区域的那部分不会被裁剪;

      Positioned

      Positioned定义如下:
      1. const Positioned({
      2. Key? key,
      3. this.left,
      4. this.top,
      5. this.right,
      6. this.bottom,
      7. this.width,
      8. this.height,
      9. required Widget child,
      10. })
  • left:距离Stack左边的距离;

  • top:距离Stack上边的距离;
  • right:距离Stack右边的距离;
  • bottom:距离Stack下边的距离;
  • width:指定当前需要定位的部件的宽度;
  • height:指定当前需要定位的部件的高度;

    需要注意的是:**Positioned****width****height**与其它地方的意义不同,在**Positioned****width****height**是用来配合**left****top****right****bottom**来定位部件的;比如在水平方向上,我们只能指定**left****right****width**三个属性中的两个属性,因为剩下的那个会根据指定的两个属性计算得到。举个例子:当我们指定了**left****width**之后,那么**right**的值就会自动计算得到(**left**+**width**)。同时指定三个属性则会报错,垂直方向同理;

Stack布局

我们创建一个Stack布局,在里边放三个Container,先来看一下默认的效果:
image.png
可以看到,先创建的部件在最下层,之后创建的部件,从里到外以此叠放在一起;

接下来,我们Positioned来修改上边Container部件的位置:
image.png
将蓝色Container距离最底层Container左边10像素,红色Container距离右边10个像素;

同样的效果,我们使用margin也能实现:
image.png
需要注意的是margin是相对于父视图而言的;

那么,如果我们同时设置了Positionedrightmargin的话,结果如何呢:
image.png
最终结果:同时设置Positionedrightmargin时,最终位置由margin决定;

如果我们只考虑部件的位置,不考虑其与父部件的关系的话,这时我们一般推荐使用Positioned,否则使用margin;需要注意的是,如果外部部件是灵活布局的话,那么margin可能将会影响外部部件的大小;

AspectRatio

除了Positioned之外,在Stack部件中,我们还经常使用一个宽高比组件AspectRatio,其定义如下:

  1. const AspectRatio({
  2. Key? key,
  3. required this.aspectRatio,
  4. Widget? child,
  5. })
  • aspectRatio:必传属性,宽高比;

我们先来看一段代码:
image.png
我们的蓝色区域为宽100,高500的矩形区域,这个时候我们使用AspectRatio来进行宽高比的设置:
image.png
我们发现,通过AspectRatio设置了宽高比之后,蓝色区域并没有发生改变,这是因为,我们将蓝色区域的heightwidth都给了固定的值,此时AspectRatio将不会生效,我们将高度去掉:
image.png
AspectRatio设置的宽高比生效了,蓝色区域的高度发生了变化,并且是宽度的2倍;

AspectRatio影响的是其父部件,父部件只需要设置宽高中的一个属性即可;AspectRatiochild属性一般不再赋值;因为child赋值的部件不受AspectRatio约束,其大小有AspectRatio影响的父部件决定;