一起来学习flutter 的布局组件

一、线性布局

我们常用的线性布局主要有两个组件Row和Column。
所谓线性布局,即指沿水平或垂直方向排列子组件。Flutter 中通过Row和Column来实现线性布局,类似于Android 中的LinearLayout控件。Row和Column都继承自Flex

Row({
  ...  
  TextDirection textDirection,    
  MainAxisSize mainAxisSize = MainAxisSize.max,    
  MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
  VerticalDirection verticalDirection = VerticalDirection.down,  
  CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
  List<Widget> children = const <Widget>[],
})

二、弹性布局

弹性布局允许子组件按照一定比例来分配父容器空间。
flutter 中的弹性布局主要通过Flex和Expanded/Flexible来配合实现。

Flex组件可以沿着水平或垂直方向排列子组件,如果你知道主轴方向,使用Row或Column会方便一些,因为Row和Column都继承自Flex,参数基本相同,所以能使用Flex的地方基本上都可以使用Row或Column。Flex本身功能是很强大的,它也可以和Expanded组件配合实现弹性布局。Expanded组件可以使Row、Column、Flex等子组件在其主轴方向上展开并填充可用空间
Expanded继承于Flexible,Flexible与Expanded的相同点是都必须使用在Row、Column、Flex其中,都可用来配置子布局的比例(权重)适配。
不同之处是Expanded会强制填充剩余留白空间,而Flexible不会强制填充

Row(
          children: <Widget>[
            Container(
              height: 30.0,
              width: 48.0,
              color: Colors.red,
            ),
            Flexible(
              flex: 1,
              child: Container(
                height: 30.0,
                width: 88.0,
                color: Colors.green,
              ),
            ),
          ],
        ),

在这里插入图片描述

Row(
          children: <Widget>[
            Container(
              height: 30.0,
              width: 48.0,
              color: Colors.red,
            ),
            Expanded(
              flex: 1,
              child: Container(
                height: 30.0,
                width: 88.0,
                color: Colors.green,
              ),
            ),
          ],
        ),

在这里插入图片描述

三、流式布局

使用row的时候,一行内容过多,右边就会溢出部分报错。这是因为 Row 默认只有一行,如果超出屏幕不会折行。我们把超出屏幕显示范围会自动折行的布局称为流式布局。Flutter 中通过Wrap和Flow来支持流式布局,将上例中的 Row 换成 Wrap 后溢出部分则会自动折行,
wrap:我们可以看到 Wrap 的很多属性在Row(包括Flex和Column)中也有,如direction、crossAxisAlignment、textDirection、verticalDirection等,这些参数意义是相同的,

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>[],
})
 Wrap(
          spacing: 8.0, // 主轴(水平)方向间距
          runSpacing: 4.0, // 纵轴(垂直)方向间距
          alignment: WrapAlignment.center, //沿主轴
          children: <Widget>[
            for (int i = 0; i < 8; i++)
              Container(
                height: 30.0,
                color: Colors.red,
                child: Text("我是Wrap"),
              ),
          ],
        ),

在这里插入图片描述

Flow组件
我们一般很少会使用Flow,因为其过于复杂,需要自己实现子 widget 的位置转换,在很多场景下首先要考虑的是Wrap是否满足需求。Flow主要用于一些需要自定义布局策略或性能要求较高(如动画中)的场景。Flow有如下优点:

性能好;Flow是一个对子组件尺寸以及位置调整非常高效的控件,Flow用转换矩阵在对子组件进行位置调整的时候进行了优化:在Flow定位过后,如果子组件的尺寸或者位置发生了变化,在FlowDelegate中的paintChildren()方法中调用context.paintChild 进行重绘,而context.paintChild在重绘时使用了转换矩阵,并没有实际调整组件位置。
灵活;由于我们需要自己实现FlowDelegate的paintChildren()方法,所以我们需要自己计算每一个组件的位置,因此,可以自定义布局策略。
缺点:
使用复杂。
Flow 不能自适应子组件大小,必须通过指定父容器大小或实现TestFlowDelegate的getSize返回固定大小。

四、层叠布局

层叠布局顾名思义就是,可以让widget叠加在一起。
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为纵轴,只要包含某个轴上的一个定位属性就算在该轴上有定位。
textDireaction:和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 时则不会。

Positioned组件

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

left、top 、right、 bottom分别代表离Stack左、上、右、底四边的距离。width和height用于指定需要定位元素的宽度和高度。注意,Positioned的width、height 和其它地方的意义稍微有点区别,此处用于配合left、top 、right、 bottom来定位组件,举个例子,在水平方向时,你只能指定left、right、width三个属性中的两个,如指定left和width后,right会自动算出(left+width),如果同时指定三个属性则会报错,垂直方向同理。

Container(
        height: 400,
        width: double.infinity,
        child: Stack(
          alignment: Alignment.center,
          children: <Widget>[
            Container(
              height: 30.0,
              color: Colors.red,
              child: Text("我是Stack"),
            ),
            Positioned(
              top: 50,
              left: 100,
              child: Container(
                height: 50,
                width: 50,
                color: Colors.red,
              ),
            )
          ],
        ),
      ),

看效果图:
在这里插入图片描述

五、相对布局

Align组件

Align({
    
    
  Key key,
  this.alignment = Alignment.center,
  this.widthFactor,
  this.heightFactor,
  Widget child,
})

alignment : 需要一个AlignmentGeometry类型的值,表示子组件在父组件中的起始位置。AlignmentGeometry 是一个抽象类,它有两个常用的子类:Alignment和 FractionalOffset,我们将在下面的示例中详细介绍。
widthFactor和heightFactor是用于确定Align 组件本身宽高的属性;它们是两个缩放因子,会分别乘以子元素的宽、高,最终的结果就是Align 组件的宽高。如果值为null,则组件的宽高将会占用尽可能多的空间。

 Container(
        height: 400,
        color: Colors.blue,
        width: double.infinity,
        child: Align(
          alignment: Alignment.center,
          child: Container(
            height: 30.0,
            color: Colors.red,
            child: Text("我是Align"),
          ),
        ),
      ),

在这里插入图片描述

六、总结

写了那么多布局组件,算是写完了。我们要根据不同的场景使用相应的布局组件,聪明的你一定会很快就掌握的。如果对你有用的话,麻烦手动点个赞,你的赞就是我写下去的动力。

猜你喜欢

转载自blog.csdn.net/hjjdehao/article/details/126012159