百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

flutter系列之:UI layout简介(flutter ui设计)

wptr33 2025-04-11 08:29 46 浏览

简介

对于一个前端框架来说,除了各个组件之外,最重要的就是将这些组件进行连接的布局了。布局的英文名叫做layout,就是用来描述如何将组件进行摆放的一个约束。

在flutter中,基本上所有的对象都是widget,对于layout来说也不例外。也就是说在flutter中layout也是用代码来完成的,这和其他的用配置文件来描述layout的语言有所不同。

你可以把layout看做是一种看不见的widget,这些看不见的widget是用来作用在可见的widget对象上,给他们实施一些限制。

flutter中layout的分类

flutter中的layout widget有很多,他们大概可以分为三类,分别是只包含一个child的layout widget,可以包含多个child的layout widget和可滑动的Sliver widgets。

这三种layout也有很多种具体的实现,对于Single-child layout widgets来说,包含下面这些widgets:

  • Align — 用来对其包含在其中的组件进行对其操作。
  • AspectRatio — 对其中的组件进行比例缩放。
  • Baseline — 通过使用子组件的baseline来进行定位。
  • Center — 自组件位于中间。
  • ConstrainedBox — 类似于IOS中的constrain,表示子组件的限制条件。
  • Container — 一个常用的widget,可以用来包含多个其他的widget。
  • CustomSingleChildLayout — 将其单个子项的布局推迟。
  • Expanded — 将Row, Column 或者 Flex的child进行扩展。
  • FittedBox — 根据fit来缩放和定位其child。
  • FractionallySizedBox — 将child按照总可用空间进行调整。
  • IntrinsicHeight — 一个将其child调整为child固有高度的小部件。
  • IntrinsicWidth — 一个将其child调整为child固有宽度的小部件。
  • LimitedBox — 限制一个box的size。
  • Offstage — 将child放入render tree中,但是却并不触发任何重绘。
  • OverflowBox — 允许child覆盖父组件的限制。
  • Padding — 为child提供padding。
  • SizedBox — 给定size的box。
  • SizedOverflowBox — 可以覆盖父组件限制的box。
  • Transform — 子组件可以变换。

以上是包含单个child的layout组件,下面是可以包含多个child的layout组件:

  • Column — 表示一列child。
  • CustomMultiChildLayout — 使用代理来定位和缩放子组件。
  • Flow — 流式布局。
  • GridView — 网格布局。
  • IndexedStack — 从一系列的child中展示其中的一个child。
  • LayoutBuilder — 可以依赖父组件大小的widget tree。
  • ListBody — 根据给定的axis来布局child。
  • ListView — 可滚动的列表。
  • Row — 表示一行child。
  • Stack — 栈式布局的组件。
  • Table — 表格形式的组件。
  • Wrap — 可以对子child进行动态调整的widget。

可滑动的Sliver widgets有下面几种:

  • CupertinoSliverNavigationBar — 是一种IOS风格的导航bar。
  • CustomScrollView — 可以自定义scroll效果的ScrollView。
  • SliverAppBar — material风格的app bar,其中包含了CustomScrollView。
  • SliverChildBuilderDelegate — 使用builder callback为slivers提供child的委托。
  • SliverChildListDelegate — 使用list来为livers提供child的委托。
  • SliverFixedExtentList — 固定axis extent的sliver。
  • SliverGrid — child是二维分布的sliver。
  • SliverList — child是线性布局的sliver。
  • SliverPadding — 提供padding的sliver。
  • SliverPersistentHeader — 可变size的sliver。
  • SliverToBoxAdapter — 包含单个box widget的Sliver。

常用layout举例

上面我们列出了所有的flutter layout,他们几乎满足了我们在程序中会用到的所有layout需求,这里我们以两个最基本和最常用的layout:Row和Column为例,来详细讲解layout的使用。

Row和Column都属于上面讲到的多个child的layout widget,它里面可以包含多个其他的widget组件。

先看一下Row和column的定义。

class Row extends Flex {
  Row({
    Key? key,
    MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
    MainAxisSize mainAxisSize = MainAxisSize.max,
    CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
    TextDirection? textDirection,
    VerticalDirection verticalDirection = VerticalDirection.down,
    TextBaseline? textBaseline, // NO DEFAULT: we don't know what the text's baseline should be
    List children = const [],
  }) : super(
    children: children,
    key: key,
    direction: Axis.horizontal,
    mainAxisAlignment: mainAxisAlignment,
    mainAxisSize: mainAxisSize,
    crossAxisAlignment: crossAxisAlignment,
    textDirection: textDirection,
    verticalDirection: verticalDirection,
    textBaseline: textBaseline,
  );
}
class Column extends Flex {
  Column({
    Key? key,
    MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
    MainAxisSize mainAxisSize = MainAxisSize.max,
    CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
    TextDirection? textDirection,
    VerticalDirection verticalDirection = VerticalDirection.down,
    TextBaseline? textBaseline,
    List children = const [],
  }) : super(
    children: children,
    key: key,
    direction: Axis.vertical,
    mainAxisAlignment: mainAxisAlignment,
    mainAxisSize: mainAxisSize,
    crossAxisAlignment: crossAxisAlignment,
    textDirection: textDirection,
    verticalDirection: verticalDirection,
    textBaseline: textBaseline,
  );
}

可以看到Row和Column都继承自Flex,并且他们的构造方法都是调用了Flex的构造方法,两者的区别就在于direction不同,Row的direction是Axis.horizontal,而Column的direction是Axis.vertical。

那么什么是Flex呢?

Flex是一个widget,在Flex中的子组件会按照某一个指定的方向进行展示。这个方向是可以控制的,比如横向或者竖向,如果你已经提前知道了主轴的方向,那么可以使用Row或者Column来替代Flex,因为这样更加简洁。

在Flex中,如果想要child在某个方向填满可用空间,则可以将该child包装在Expanded中。

要注意的是,Flex是不可滚动的,如果Flex中的child太多,超出了Flex中的可用空间,那么Flex将会报错,所以如果你需要展示很多child的情况下,可以考虑使用可滚动的组件,比如ListView。

如果你只有一个child,那么就没有必要使用Flex或者Row和Column了,可以考虑使用Align或者Center来对child进行定位。

在Flex中有几个非常重要的参数,比如mainAxisAlignment表示的是子组件沿主轴方向的排列规则,mainAxisSize表示的是主轴的size大小,crossAxisAlignment表示的是和主轴垂直轴的子组件排列规则。当然还有它最最重要的children属性,children是一个Widget的list列表,用来存储要展示的子组件。

以Row为例,我们创建一个简单的RowWidget:

class RowWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      textDirection: TextDirection.ltr,
      children: [
        YellowBox(),
        YellowBox(),
        YellowBox(),
      ],
    );
  }
}

这里我们返回了一个Row对象,设置了textDirection和children属性。

children里面是自定义的YellowBox:

class YellowBox extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(
        color: Colors.yellow,
        border: Border.all(),
      ),
    );
  }
}

YellowBox是一个长和宽都是50的正方形。我们这里使用了BoxDecoration对其上色。

最后将RowWidget放到Scaffold的body里面,如下所示:

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: RowWidget()
    );
  }

我们可以看到下面的图像:

大家可以看到YellowBox是紧贴在一起的,如果我们想要均匀分别该如何做呢?

我们可以在Row中添加一个属性叫做mainAxisAlignment,取值如下:

mainAxisAlignment: MainAxisAlignment.spaceEvenly

重新运行,生成的图像如下:

上面我们还提到了一个Expanded组件,可以用来填充剩余的可用空间,我们把最后一个YellowBox用Expanded围起来,如下所示:

    return Row(
      textDirection: TextDirection.ltr,
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        YellowBox(),
        YellowBox(),
        Expanded(
          child: YellowBox(),
        )
      ],
    );

生成的图像如下:

可以看到最后一个Box填充到了整个Row剩余的空间。

大家要注意,这时候mainAxisAlignment是没有效果的。

如果观察Expanded的构造函数,可以看到Expanded还有一个flex属性:

  const Expanded({
    Key? key,
    int flex = 1,
    required Widget child,
  }) : super(key: key, flex: flex, fit: FlexFit.tight, child: child);

flex属性表示的是flex factor,默认值是1,还是上面的例子,我们将flex调整为2,看看效果:

children: [
        YellowBox(),
        YellowBox(),
        Expanded(
          flex:2,
          child: YellowBox(),
        )
      ],

运行的结果和flex=1是一样的,为什么呢?

事实上这个flex表示的是相对于其他Expanded的组件所占用的空间比例。我们可以讲所有的子组件都用Expanded进行扩充,然后再看看效果:

      children: [
        Expanded(
          child: YellowBox(),
        ),
        Expanded(
          child: YellowBox(),
        ),
        Expanded(
          flex: 2,
          child: YellowBox(),
        )
      ],

运行结果如下:

可以看到最后一个child占用的空间是前面两个的两倍。

如果我们想要在YellowBox中间添加空格怎么办呢?有两种方法。

第一种方法是使用SizedBox,如下:

children: [
        Expanded(
          child: YellowBox(),
        ),
        SizedBox(
          width: 100,
        ),
        Expanded(
          child: YellowBox(),
        ),
        Expanded(
          flex: 2,
          child: YellowBox(),
        )
      ],

SizedBox里面可以包含子child,从而重新设置子child的长度和高度。如果不包含子child则会生成一个空格。

还有一种方式是使用Spacer,如下所示:

      children: [
        Expanded(
          child: YellowBox(),
        ),
        Spacer(flex: 2),
        Expanded(
          child: YellowBox(),
        ),
        Expanded(
          flex: 2,
          child: YellowBox(),
        )
      ],

生成的图像如下:

Spacer和SizedBox都可以生成空白,不同的是Spacer可以和flex一起使用,而SizedBox必须固定size大小。

总结

以上就是fluter中layout和的分类和基本layout Row和Column的使用情况了。

本文的例子:
https://github.com/ddean2009/learn-flutter.git

更多内容请参考
http://www.flydean.com/07-flutter-ui-layout-overview/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

相关推荐

MySQL进阶五之自动读写分离mysql-proxy

自动读写分离目前,大量现网用户的业务场景中存在读多写少、业务负载无法预测等情况,在有大量读请求的应用场景下,单个实例可能无法承受读取压力,甚至会对业务产生影响。为了实现读取能力的弹性扩展,分担数据库压...

Postgres vs MySQL_vs2022连接mysql数据库

...

3分钟短文 | Laravel SQL筛选两个日期之间的记录,怎么写?

引言今天说一个细分的需求,在模型中,或者使用laravel提供的EloquentORM功能,构造查询语句时,返回位于两个指定的日期之间的条目。应该怎么写?本文通过几个例子,为大家梳理一下。学习时...

一文由浅入深带你完全掌握MySQL的锁机制原理与应用

本文将跟大家聊聊InnoDB的锁。本文比较长,包括一条SQL是如何加锁的,一些加锁规则、如何分析和解决死锁问题等内容,建议耐心读完,肯定对大家有帮助的。为什么需要加锁呢?...

验证Mysql中联合索引的最左匹配原则

后端面试中一定是必问mysql的,在以往的面试中好几个面试官都反馈我Mysql基础不行,今天来着重复习一下自己的弱点知识。在Mysql调优中索引优化又是非常重要的方法,不管公司的大小只要后端项目中用到...

MySQL索引解析(联合索引/最左前缀/覆盖索引/索引下推)

目录1.索引基础...

你会看 MySQL 的执行计划(EXPLAIN)吗?

SQL执行太慢怎么办?我们通常会使用EXPLAIN命令来查看SQL的执行计划,然后根据执行计划找出问题所在并进行优化。用法简介...

MySQL 从入门到精通(四)之索引结构

索引概述索引(index),是帮助MySQL高效获取数据的数据结构(有序),在数据之外,数据库系统还维护者满足特定查询算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构...

mysql总结——面试中最常问到的知识点

mysql作为开源数据库中的榜一大哥,一直是面试官们考察的重中之重。今天,我们来总结一下mysql的知识点,供大家复习参照,看完这些知识点,再加上一些边角细节,基本上能够应付大多mysql相关面试了(...

mysql总结——面试中最常问到的知识点(2)

首先我们回顾一下上篇内容,主要复习了索引,事务,锁,以及SQL优化的工具。本篇文章接着写后面的内容。性能优化索引优化,SQL中索引的相关优化主要有以下几个方面:最好是全匹配。如果是联合索引的话,遵循最...

MySQL基础全知全解!超详细无废话!轻松上手~

本期内容提醒:全篇2300+字,篇幅较长,可搭配饭菜一同“食”用,全篇无废话(除了这句),干货满满,可收藏供后期反复观看。注:MySQL中语法不区分大小写,本篇中...

深入剖析 MySQL 中的锁机制原理_mysql 锁详解

在互联网软件开发领域,MySQL作为一款广泛应用的关系型数据库管理系统,其锁机制在保障数据一致性和实现并发控制方面扮演着举足轻重的角色。对于互联网软件开发人员而言,深入理解MySQL的锁机制原理...

Java 与 MySQL 性能优化:MySQL分区表设计与性能优化全解析

引言在数据库管理领域,随着数据量的不断增长,如何高效地管理和操作数据成为了一个关键问题。MySQL分区表作为一种有效的数据管理技术,能够将大型表划分为多个更小、更易管理的分区,从而提升数据库的性能和可...

MySQL基础篇:DQL数据查询操作_mysql 查

一、基础查询DQL基础查询语法SELECT字段列表FROM表名列表WHERE条件列表GROUPBY分组字段列表HAVING分组后条件列表ORDERBY排序字段列表LIMIT...

MySql:索引的基本使用_mysql索引的使用和原理

一、索引基础概念1.什么是索引?索引是数据库表的特殊数据结构(通常是B+树),用于...