Flutter 布局(流式,层叠)

2021/4/18 posted in  Flutter

首先什么是流式布局,我们把超出屏幕显示范围会自动折行的布局称为流式布局。在 Flutter 中有 Widget WrapFlow

Wrap

看一下 Wrap的定义:

Wrap({
  ...
  this.direction = Axis.horizontal,
  this.alignment = WrapAlignment.start,
  this.spacing = 0.0,
  this.runAlignment = WrapAlignment.start,
  this.runSpacing = 0.0,
  this.crossAxisAlignment = WrapCrossAlignment.start,
  this.textDirection,
  this.verticalDirection = VerticalDirection.down,
  List<Widget> children = const <Widget>[],
})

大部分的特性跟 Flex 和 Column 相同,有几个其特有的属性可以介绍下:

  • spacing:主轴方向子widget的间距
  • runSpacing:纵轴方向的间距
  • runAlignment:纵轴方向的对齐方式

iOS 中的 UIStackView 与Wrap类似

Flow

Flow 一般用于需要自定义布局策略或者性能要求较高的场景。
在很多场景下首先要考虑 Warp 是否满足需求。
其优点有:

  1. 性能好,Flow使用转换矩阵对子组件进行位置调整的时候进行优化。
  2. 灵活,体现在可以自己计算每一个组件的位置,可以自定义布局策略。

缺点:

  1. 使用复杂
  2. 不能自适应子组件的大小,必须通过指定父容器大小或实现 TestFlowDelegategetSize 返回固定大小。

Flutter 层叠布局

层叠布局在Flutter中对应的组件是 Stack, Positioned,两者搭配实现绝对定位。

Stack 允许子 Widget 堆叠, Positioned 用于根据 Stack 的四个角确定子组件的位置。

Stack

Stack({
  this.alignment = AlignmentDirectional.topStart,
  this.textDirection,
  this.fit = StackFit.loose,
  this.overflow = Overflow.clip,
  List<Widget> children = const <Widget>[],
})
  • alignment:此参数决定如何去对齐没有定位(没有使用Positioned)或部分定位的子组件。所谓部分定位,在这里特指没有在某一个轴上定位:left、right为横轴,top、bottom为纵轴,只要包含某个轴上的一个定位属性就算在该轴上有定位。
  • textDirection:和Row、Wrap的textDirection功能一样,都用于确定alignment对齐的参考系,即:textDirection的值为TextDirection.ltr,则alignment的start代表左,end代表右,即从左往右的顺序;textDirection的值为TextDirection.rtl,则alignment的start代表右,end代表左,即从右往左的顺序。
  • fit:此参数用于确定没有定位的子组件如何去适应Stack的大小。StackFit.loose表示使用子组件的大小,StackFit.expand表示扩伸到Stack的大小。
  • overflow:此属性决定如何显示超出Stack显示空间的子组件;值为Overflow.clip时,超出部分会被剪裁(隐藏),值为Overflow.visible 时则不会。

Flutter 布局中的 Stack 跟 iOS中的UIStackView 概念完全不一样,在Flutter 中Stack 它是Widget可堆叠的一种描述,仅仅确定了适应大小模式,定位方向等,UIStackView 更像是Flutter中的 Stack 搭配 Wrap 使用的一种组合形式。

Positioned

const Positioned({
  Key key,
  this.left, 
  this.top,
  this.right,
  this.bottom,
  this.width,
  this.height,
  @required Widget child,
})

举个使用的例子吧:

//通过ConstrainedBox来确保Stack占满屏幕
ConstrainedBox(
  constraints: BoxConstraints.expand(),
  child: Stack(
    alignment:Alignment.center , //指定未定位或部分定位widget的对齐方式
    children: <Widget>[
      Container(child: Text("Hello world",style: TextStyle(color: Colors.white)),
        color: Colors.red,
      ),
      Positioned(
        left: 18.0,
        child: Text("I am Jack"),
      ),
      Positioned(
        top: 18.0,
        child: Text("Your friend"),
      )        
    ],
  ),
);

Stack 和 Positioned 搭配使用可以实现绝对定位,Stack 能不能跟其他组件搭配使用呢?

Stack 允许子 Widget 堆叠, Positioned 用于根据 Stack 的四个角确定子组件的位置。

这个组合是必须的吗?