本篇基于Flutter 3.13.9,Dart 3.1.5版别

Flutter 3.13.9 • channel stable • github.com/flutter/flu…

Framework • revision d211f42860 (2 weeks ago) • 2023-10-25 13:42:25 -0700

Engine • revision 0545f8705d

Tools • Dart 3.1.5 • DevTools 2.25.0

本篇为Flutter基建的第五篇文章了,首要介绍Flutter中布局相关的组件,此篇文章涵盖了日常开发中常常运用的一些布局组件,希望咱们能够经过本篇文章了解和了解Flutter中布局组件的相关常识。

Flutter基建 - 布局组件全面解析

Flutter基建 – Dart根底类型

Flutter基建 – Dart办法和类

Flutter基建 – 文本组件

Flutter基建 – 按钮全解析

Flutter基建 – 布局组件全面解析

线性组件

Flutter中线性布局供给了横向和纵向两种,Row为横向行布局,Column为纵向列布局,这两种布局类似于Android原生的LinearLayout,下面咱们看看Row和Column的详细运用。

Row行组件

Row(
  mainAxisAlignment: MainAxisAlignment.start,
  mainAxisSize: MainAxisSize.max,
  crossAxisAlignment: CrossAxisAlignment.start,
  children: [
    Container(
      width: 100,
      height: 100,
      color: Colors.red,
    ),
    Container(
      width: 100,
      height: 100,
      color: Colors.blue,
    ),
    const Text('Text'),
  ],
),

上述代码就完结了一个最根底的Row组件,内部包含了两个100像素容器和一个文本,这儿咱们需求重视重点参数为:

  • mainAxisAlignment:主轴的对齐办法,Row组件中主轴为x轴,能够设置start、end和center等办法;
  • mainAxisSize:主轴巨细,也就是Row的宽度,可设置为max和min;
  • crossAxisAlignment:纵轴的对齐办法,Row组件中纵轴为y轴,也能够设置start、end和center等办法;
  • children:这个参数就不用多加介绍了,子组件。

了解完以上参数之后咱们看下上述主轴为start对齐、主轴巨细为max和纵轴为start对齐的详细作用:

Flutter基建 - 布局组件全面解析

Flutter基建 - 布局组件全面解析

下面是Flutter Inspector形式下的界面,能够清楚的看到Row的宽度为屏幕宽度,然后全体布局是靠左对齐,笔直方向为靠上对齐,接着咱们将mainAxisAlignment和crossAxisAlignment都改为center再看下作用:

Flutter基建 - 布局组件全面解析

全体布局水平缓笔直方向都变成了居中对齐了,这就是main和cross的alignment运用的作用。

终究咱们再来看下mainAxisSize中max和min两种区别,上面咱们界说的是max办法,然后咱们将max改为min,mainAxisAlignment依旧为center,看看作用:

Flutter基建 - 布局组件全面解析

经过作用图能够看出Row的全体宽度不再是屏幕的宽度了,而是子组件的叠加宽度,此刻MainAxisAlignment.center也不再具有作用,Column的宽度和子组件的叠加宽度共同也天然满足了居中的作用了。

Column列组件

了解了Row组件运用办法之后,Column上手就有如鱼得水,它其实就是笔直方向上的Row组件,下面咱们也简略看下Column的运用办法。

Column(
  mainAxisAlignment: MainAxisAlignment.center,
  mainAxisSize: MainAxisSize.max,
  crossAxisAlignment: CrossAxisAlignment.center,
  children: [
    Container(
      width: 100,
      height: 100,
      color: Colors.red,
      child: const Text('Red Container'),
    ),
    Container(
      width: 100,
      height: 100,
      color: Colors.blue,
      child: const Text('Blue Container'),
    ),
    const Text('Text'),
  ],
),

Flutter基建 - 布局组件全面解析

经过Inspector作用图能够看出,Column组件的高度是除状态栏和标题栏之后的整个高度,而宽度则变成了子组件的最大宽度,用法和Row基本是共同的,只需求注意主轴和纵轴的区分就能够了,这儿就不再过多介绍了哈。

叠加组件

Stack组件

Stack组件看姓名有点难以了解,仓库组件是啥个意思呢?其实就是依照指定的对齐办法顺次往上叠加的一种组件,子组件会依照次序顺次叠加在层次上,最上面的组件会盖住基层的组件,下面咱们先了解下最简略的Stack组件完结办法。

Stack(
  children: [
    Container(
      width: 100,
      height: 100,
      color: Colors.blue,
    ),
    Container(
      width: 50,
      height: 50,
      color: Colors.red,
    ),
    const Text('Text'),
  ],
),

Flutter基建 - 布局组件全面解析

上面代码中Stack组件只设置了children一个参数,内部包含了100像素的蓝色Container、50像素的赤色Container和一个文本组件,终究的作用如上图所示,它们依照次序顺次叠加到Stack中,赤色的Container遮住了蓝色的Container一部分,接下来咱们在增加额外参数试试作用。

Stack(
  alignment: AlignmentDirectional.center,
  children: [
    Container(
      width: 100,
      height: 100,
      color: Colors.blue,
    ),
    Container(
      width: 50,
      height: 50,
      color: Colors.red,
    ),
    const Text('Text'),
  ],
),

咱们给Stack指定了alignment参数为AlignmentDirectional.center特点,它的默认值为AlignmentDirectional.topStart,这时分Stack子组件应该是依照居中的办法来顺次叠加,作用如下:

Flutter基建 - 布局组件全面解析

再来看看Stack中fit参数,fit参数默认值为StackFit.loose,意思是Stack不会干扰子组件的巨细,子组件该多大就是多大,也就是上面咱们看到的作用,两个Container都是选用的本身界说的长宽;fit还有一张就是StackFit.expand,这个值就比较有意思,它会让未定位的(这儿在Positioned组件中会介绍)子组件疏忽掉本身的巨细,然后变成Stack的巨细,咱们来看看详细作用:

SizedBox(
  width: 200,
  height: 200,
  child: Stack(
    fit: StackFit.expand,
    children: [
      Container(
        width: 100,
        height: 100,
        color: Colors.blue,
      ),
      Container(
        width: 50,
        height: 50,
        color: Colors.red,
      ),
      const Text('Text'),
    ],
  ),
),

Flutter基建 - 布局组件全面解析

这儿咱们运用SizeBox将Stack的长宽束缚为200,然后子组件中Container长宽不变,然而终究的作用却是Container的长宽都变成了200,本身设置的长宽参数失效了,这就导致有或许最上面的子组件会将下方所有的组件都给遮盖住,所以咱们在日常开发运用中仍是要按需选用哈。

Positioned组件

Positioned组件能够依据左上右下四个方位来完结组件的肯定定位,合作Stack能够完美的将子组件定位在Stack中,Positioned组件的构造办法十分简略:

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

能够设置left、top、right和bottom来完结四个方位的界说作用;width和height用于设置组件的长度和宽度特点。

Stack(
  children: [
    Positioned(
      left: 20,
      child: Container(
        width: 100,
        height: 100,
        color: Colors.blue,
      ),
    ),
    Positioned(
      left: 50,
      top: 50,
      child: Container(
        width: 50,
        height: 50,
        color: Colors.red,
      ),
    ),
  ],
),

Flutter基建 - 布局组件全面解析

经过Positioned的left和top咱们就能够将本身的方位精准的定位到指定的坐标。

在上面介绍Stack组件的时分咱们提到了StackFit.expand能够将未定位的子组件扩展到本身的巨细,而经过定位的子组件也会有同样的作用么,咱们实践下试试作用:

SizedBox(
  width: 200,
  height: 200,
  child: Stack(
    fit: StackFit.expand,
    children: [
      Container(
        width: 150,
        height: 150,
        color: Colors.black,
      ),
      Positioned(
        left: 20,
        child: Container(
          width: 100,
          height: 100,
          color: Colors.blue,
        ),
      ),
      Positioned(
        left: 50,
        top: 50,
        child: Container(
          width: 50,
          height: 50,
          color: Colors.red,
        ),
      ),
    ],
  ),
),

上面代码中咱们将Stack组件的fit特点设置为StackFit.expand,子组件中巨细为150的Container为运用Positioned进行定位,后边两个都包裹了Positioned组件进行定位,在这种情况下,expand特点只会将巨细150的Container扩展到本身200像素的巨细,而运用Positioned包裹的Container则不会改动巨细,这就是expand在Positioned下特殊的作用,详细界面如下:

Flutter基建 - 布局组件全面解析

流式组件

Wrap组件

Warp组件作为Flutter供给的流式布局,在用法上面也是供给了十分多的可装备性,可设置主轴方向,包含主轴和纵轴的对其办法、子布局在主轴和纵轴方向的边距特点,下面咱们就看看Wrap是怎么进行装备的吧~

Widget buildWrap(BuildContext context) {
  List<Color> containerColor = [Colors.black, Colors.red, Colors.blue, Colors.green, Colors.amber];
  return buildScaffold(
    context,
    SizedBox(
      width: double.maxFinite,
      height: double.maxFinite,
      child: Wrap(
        direction: Axis.horizontal,
        spacing: 10,
        runSpacing: 10,
        alignment: WrapAlignment.center,
        runAlignment: WrapAlignment.center,
        verticalDirection: VerticalDirection.down,
        children: [
          buildContainer(containerColor[0]),
          buildContainer(containerColor[1]),
          buildContainer(containerColor[2]),
          buildContainer(containerColor[3]),
          buildContainer(containerColor[4]),
      	],
    	),
  	),
	);
}
Container buildContainer(Color containerColor) {
  return Container(
    width: 100,
    height: 100,
    color: containerColor,
  );
}

这儿咱们先经过SizeBox将Wrap长度和宽度都设置为充溢屏幕,然后经过direction将主轴方向设置为水平方向,spacing参数为主轴方向子组件的边距,runSpacing参数为纵轴方向上子组件的边距,alignment参数为主轴方向子组件的对齐办法,runAlignment参数为纵轴方向子组件的对齐办法,verticalDiretion这个参数为笔直方向是怎么摆放,这儿运用的默认值down,先来看看作用,终究咱们会独自介绍verticalDirection参数。

Flutter基建 - 布局组件全面解析

经过上面作用图能够看出,一行只够三个Container的宽度,当摆放不下的时分自动转到下一行,并且在主轴和纵轴方向上都是居中摆放。

这时分5个Container都是依照次序顺次摆放下来,此刻咱们将verticalDirection改为up再来看看是怎么摆放的。

Flutter基建 - 布局组件全面解析

能够看到5个Container的上下方位颠倒过来了,不需求咱们改动Container的次序,只需求将VerticalDiraction设置为up即可。

Flow组件

Flow组件也是能够达到Wrap一样的流式布局的作用,但是它的完结要复杂的多,假如不是定制化的流式布局不建议运用Flow来完结,Flow需求自界说FLowDelegate来完结子组件的摆放组合。

下面咱们来简略完结一个类似于Wrap的作用。

Widget buildFlow(BuildContext context) {
  List<Color> containerColor = [Colors.black, Colors.red, Colors.blue, Colors.green, Colors.amber];
  return buildScaffold(
    context,
    Flow(
      delegate: BuildFlowDelegate(),
      children: [
        buildContainer(containerColor[0]),
        buildContainer(containerColor[1]),
        buildContainer(containerColor[2]),
        buildContainer(containerColor[3]),
        buildContainer(containerColor[4]),
      ],
    ),
  );
}
class BuildFlowDelegate extends FlowDelegate {
  double width = 0;
  double height = 0;
  BuildFlowDelegate();
  @override
  void paintChildren(FlowPaintingContext context) {
    var x = 0.0;
    var y = 0.0;
    for (int i = 0; i < context.childCount; i++) {
      var childX = context.getChildSize(i)!.width + x;
      // 假如一行剩下的宽度还够制作一个子组件,那么就在这行持续制作;
      // 假如一行剩下宽度已经不行制作一个子组件了,那么就换行开端制作。
      if (childX < context.size.width) {
        context.paintChild(i, transform: Matrix4.translationValues(x, y, 0.0));
        x = childX;
      } else {
        x = 0;
        y += context.getChildSize(i)!.height;
        context.paintChild(i, transform: Matrix4.translationValues(x, y, 0.0));
        x += context.getChildSize(i)!.width;
      }
    }
  }
  @override
  bool shouldRepaint(covariant FlowDelegate oldDelegate) {
    return oldDelegate != this;
  }
}

BuildFlowDelegate类就是自界说的FlowDelegte,需求在它的paintChildren办法中完结子组件的摆放规矩,这儿咱们选用的是最简略一行剩下宽度是否满足制作下一个子组件的规矩来制作,这儿咱们没有考虑给子组件设置边距的特点,只是在判别条件中考虑了组件的宽度,详细完结的作用如下所示:

Flutter基建 - 布局组件全面解析

Flow在完结普通流式布局的场景下过于复杂了,一般直接考虑运用Wrap来完结即可,假如Wrap组件不满足你的实线要求,这时分就能够选用Flow来作一些特殊的定制化作用。

束缚组件

Flutter中束缚组件首要针对的是布局的巨细进行约束,它能够很好的协助咱们管理组件的巨细,也是本篇文章最简略的一节内容了,下面咱们逐个看下ConstrainedBox、UnConstrainedBox和SizeBox的详细运用办法。

ConstrainedBox组件

ConstrainedBox束缚首要是经过constraints参数来决定,它能够约束最小宽高和最大宽高特点。

Widget buildConstraints(BuildContext context) {
  return buildScaffold(
    context,
    ConstrainedBox(
      constraints: const BoxConstraints(minWidth: 50, minHeight: 50, maxWidth: 200, maxHeight: 200),
      child: Container(
        width: 10,
        height: 10,
        color: Colors.red,
      ),
    ),
  );
}

这儿咱们将ConstrainedBox的最小宽高设置为50,最大宽高设置为200,然后它的子组件Container宽高设置为10,此刻Container终究显现宽高则被constraints的特点约束了,并没有选用本身10像素的巨细,而是变成constraints的最小宽高50。

Flutter基建 - 布局组件全面解析

假如咱们将Container的宽高设置为500,那么它也会被constraints最大宽高200给约束,并不能达到本身500的巨细。

这时分咱们将不被ConstrainedBox给约束该怎么完结呢,就需求UnConstrainedBox来撤销约束了。

UnConstrainedBox组件

Widget buildConstraints(BuildContext context) {
  return buildScaffold(
    context,
    ConstrainedBox(
      constraints: const BoxConstraints(minWidth: 50, minHeight: 50, maxWidth: 200, maxHeight: 200),
      child: UnconstrainedBox(
        child: Container(
          width: 10,
          height: 10,
          color: Colors.red,
        ),
      ),
    ),
  );
}

这儿即便ConstrainedBox设置了最小宽高50的约束,咱们仍然能够经过UnconstrainedBox来撤销这一约束,Container会依照本身的巨细进行制作。

Flutter基建 - 布局组件全面解析

SizeBox组件

SizeBox和ConstrainedBox不同的是,ConstrainedBox约束的是一个规模,而SizeBox约束的是详细值,SizeBox需求传入详细的宽高值,子组件需求依照这个值进行制作。

Widget buildSizeBox(BuildContext context) {
  return buildScaffold(
    context,
    SizedBox(
      width: 100,
      height: 100,
      child: Container(
        width: 200,
        height: 200,
        color: Colors.red,
      ),
    ),
  );
}

这儿即便Container设置了宽高为200的特点,但是上层的SizeBox只设置了宽高100的特点,所以Container只能依照SizeBox设置的巨细进行制作。

Flutter基建 - 布局组件全面解析

写在终究

本篇文章全面的介绍了Flutter中布局组件的相关常识,希望能够协助咱们了进一步了解和了解布局组件的相关常识,后续会循序渐进逐步接触Flutter更多的常识。

我是Taonce,假如觉得本文对你有所协助,帮忙重视、赞或者收藏三连一下,谢谢~