Flutter 布局基础教程

欢迎来到 Flutter 布局 codelab!你将在这里学到如何构建 Flutter UI,更棒的是这一切都不需要安装 Flutter 或者 Dart!

 重点提醒

这个 codelab 涵盖了 Flutter 的基本布局概念,并且将会使用一个叫做 DartPad 的实验性代码编辑器。DartPad 并没有在所有浏览器上进行严格测试,如果你在任何特定浏览器上使用 DartPad 遇到了问题,请创建一个 DartPad issue 并指明是哪个浏览器。

Flutter 与其他框架有着明显的差异,原因在于它使用代码来构建 UI,而不是 XML 或其他东西。其中,Widget 是构建 Flutter UI 的基本单元。当你逐渐深入这个 codelab,你将会发现在 Flutter 中几乎所有的东西都是 Widget。Widget 是一个不会改变的对象,它是 UI 中一个特定部分的描述。你还会学到 Flutter 的 Widget 非常容易组合,这意味着你能够通过组合已有的 Widgets 来创造更多复杂的 Widgets。到这篇文章的最后,你会运用这里所学的知识构建一个显示名片的 Flutter UI。

本 codelab 的预期完成时间约为 45 - 60 分钟

1. Row 和 Column 类

Row 和 Column 是两个用来容纳和布局 Widgets 的类。在它们内部的 Widgets 我们称为 children, Row 和 Column 就作为它们的父级。 Row 将会让 Widgets 水平排列,而 Column 则会让其竖直排列。

样例:创建一个 Column

下面的样例将会显示 Row 和 Column 的区别。

1. 点击 运行 按钮。

2. 在这段代码中,将 Row  改为 Column  并再次运行。

2. 轴大小和对齐方式

至此, BlueBox  widget 已经在一起被压扁了(在界面的左边或者上面)。你可以通过轴大小和对齐属性来改变  BlueBox  Widget 的间距。

2.1 mainAxisSize 属性

Row  和  Column 分别占据了不同的主轴。 Row  的主轴是水平的。  mainAxisSize  决定了  Row  和  Column  能够在主轴上占据多大空间。 mainAxisSize  有两个可选属性:
MainAxisSize.max  
Row  和  Column  占据它们主轴上所有空间。如果子 Widget 的总宽度小于主轴上的空间,它们就会充满剩余的空间。
MainAxisSize.min  
Row  和  Column  仅占据它的 children 在主轴上所需的空间,它的 children 在主轴之间将没有额外空间。
小提示
mainAxisSize  默认为  MainAxisSize.max 。如果你不特别指定其他的值,就会使用默认值,就像我们前一个样例中展示的那样。
样例:自定义轴大小
下面的样例将会特别指定  mainAxisSize  为其默认值  MainAxisSize.max
1. 点击 运行 按钮。
2. 将  MainAxisSize.max  改为  MainAxisSize.min ,并再次运行。
2.2 mainAxisAlignment 属性
当  mainAxisSize  被设为  MainAxisSize.max Row  和  Column  将会使用额外空间来对齐它的 children。  mainAxisAlignment  属性决定了  Row  和  Column  将会在额外空间中如何对齐它的 children。  mainAxisAlignment  有以下六个可选属性:
MainAxisAlignment.start  
将其 children 从主轴起点处开始对齐。( Row  的起点在左边, Column  的起点在顶部)
MainAxisAlignment.end  
将其 children 从主轴终点处开始对齐。( Row  的终点在右边, Column  的终点在底部)
MainAxisAlignment.center  
将其 children 置于主轴中心。
MainAxisAlignment.spaceBetween  
在 children 之间平均分配额外空间。
MainAxisAlignment.spaceEvenly  
在 children 之间,以及第一个 children 之前和最后一个 children 之后,平均分配额外空间。
MainAxisAlignment.spaceAround  
与  MainAxisAlignment.spaceEvenly  相似,但在第一个 child 之前以及最后一个孩子之后减少了一半的空间,让其 children 之间宽度缩减一半。
样例:自定义主轴对齐方式
下面的样例将特别指定  mainAxisAlignment  为其默认值,  MainAxisAlignment.start
1. 点击 运行 按钮。

2. 将 MainAxisAlignment.start改为 MainAxisAlignment,然后再次运行。

小提示
在阅读下一个小节之前,将  MainAxisAlignment.end  换成其他值试试看。

2.3 crossAxisAlignment 属性

crossAxisAlignment  属性决定了  Row  和  Column  能够如何在其横轴上定位 children。  Row  的横轴是竖直的,而  Column  则是水平的。绝大多数  crossAxisAlignment  属性仅在  Row  中生效。  crossAxisAlignment  属性有五个可选属性:
CrossAxisAlignment.start  
将其 children 横轴顶部对齐。(只在  Row  中生效)
CrossAxisAlignment.end  
将其 children 横轴底部对齐。(只在  Row  中生效)
CrossAxisAlignment.center  
将其 children 横轴中心对齐。(只在  Row  中生效)
CrossAxisAlignment.stretch  
沿横轴延伸 children。(在  Row  中是从顶至底, Column  则是从左至右)
CrossAxisAlignment.baseline  
根据 children 的基线对子节点。(仅限 Text 类,并要求  textBaseline  属性设置为  TextBaseline.alphabetic
样例:自定义横轴对齐方式
下面的样例将特别指定  crossAxisAlignment  为其默认值,  CrossAxisAlignment.center
为了演示横轴对齐方式, mainAxisAlignment  被设为  MainAxisAlignment.spaceAround Row  现在包含一个比 “BlueBox” Widget 更高的  BiggerBlueBox  Widget。
1. 点击**运行**按钮。
2. 将  CrossAxisAlignment.center  改为  CrossAxisAlignment.start ,并再次运行。
小提示
在阅读下一个小节之前,将  CrossAxisAlignment.start  改为其他值试试。

3. Flexible widget

正如你所看到, mainAxisAlignment  和  crossAxisAlignment  属性决定了  Row  和  Column 在各个轴上如何布局 widget。  Row  和  Column  首先布置固定大小的 widget。固定大小的小部件被认为是 不灵活的 因为它们布局后无法自我调整大小。
Flexible  widget 包裹一个 widget 让这个 widget 变得可以调整大小。当  Flexible  widget 包裹 widget 时,这个 Widget 就成为  Flexible  widget 的子节点,并被视为 flexible 的。在布置固定大小的 widget 后, Flex 的 widget 根据其  flex  和  fit  属性调整大小:
flex  
将自身的  flex  因子与其他的比较,以决定自身占剩余空间的比例。
fit  
决定  Flexible  的 Widget 是否能够填充所有剩余空间。

样例:改变 fit 属性

下面的样例演示了  fit  属性,它可以使用这两个值之一:
FlexFit.loose  
使用 Widget 的自身作为首选大小。(默认情况下)
FlexFit.tight  
强制 Widget 充满所有剩余空间。
在这个样例中,改变  fit  属性使  Flexible  widgets 能够填充剩余空间。
1. 点击 运行 按钮。
2. 将所有  fit  的值设为  FlexFit.tight ,并再次运行。
样例:测试 flex 值
在下面这个例子中, Row  包含了一个  BlueBox  widget 和两个  Flexible  widgets 包裹的  BlueBox  Widget。  Flexible widgets 包含了  flex  属性,并将其值设为 1。(默认值)
当  flex  属性互相比较时,它们的  flex  值的比率决定了  Flexible  Widget 自身所占剩余空间的比例。
  remainingSpace * (flex / totalOfAllFlexValues)
在这个例子中, flex  值的总和为(2),这决定了每个  Flexible  widgets 都能分到总剩余空间的一半空间。 BlueBox widget(或是 fixed-size widget)得到了相同的大小。
 小提示
在阅读下个样例之前,尝试将  flex  属性转换为其他值,例如 2 和 1。

4. Expanded widget

Expanded  widget 能够包裹一个 Widget 并强制其填满剩余空间,与  Flexible  非常相似。
 小提示
Flexible 和 Expanded 有何不同呢?  使用  Flexible  在  Row  或  Column  中重新调整 widgets 的大小。这样,你就可以调整子 Widget 的间距同时保持其相对于父 Widget 的大小。  Expanded  改变子窗口小部件的约束,所以它会填补全部空白空间。
样例:填补额外空间
下面的示例演示  Expanded  widget  如何强制子窗口小部件填补额外空间。
1. 点击 运行 按钮。
2. 在第二个  BlueBox  widget 外包裹一个  Expanded  widget。
例如:
  Expanded(child: BlueBox(),),
3. 点击 Format (格式化) 按钮格式化你的代码,再重新运行一次。

5. SizedBox widget

SizedBox  widget 的两种用途之一就是创建精确的尺寸。当  SizedBox  包裹了一个 Widget 时,它会使用  height  和  width  调整其大小。如果它没有包裹 Widget,它可以使用 height width 属性创造空的空间。
样例:调整一个 widget
下面的样例使用  SizedBox  widget 包裹了中间的  BlueBox  widget,并将  BlueBox  的宽度设为 100 逻辑像素。
1. 点击 运行 按钮。
2. 将  SizedBox  widget 中的  height  设为 100 逻辑像素,并重新运行。
样例:创建空间
下面的样例将会包含三个  BlueBox  widget,其中第一个和第二个  BlueBox  widget 包裹  SizedBox SizedBox  widget 的  width  设为 50 逻辑像素。
1. 点击 运行 按钮。
2. 通过在第二个和第三个  BlueBox  widget 之间添加另一个 SizedBox widget (宽 25 逻辑像素)以创建更多空间。

6. Spacer widget

与  SizedBox  相似, Spacer  widget 也能在 Widgets 之间创建空间。
小提示
SizedBox 和 Spacer 有何不同?  如果你想用  flex  属性创建一段空间,请使用  Spacer 。如果你想创建一个拥有特定逻辑像素值的空间,请使用  SizedBox
Example:创建更多空间

下面的样例使用  flex  值为 1 的  Spacer  widget,分隔最初的两个  BlueBox  widget。
1. 点击 运行 按钮。
2. 在第二个和第三个 BlueBox  widget 之间添加另一个 Spacer  widget。(flex 值仍然为 1)

7. Text widget

Text  widget 不仅能够显示文字,并能够配置不同的字体,大小和颜色。
8. Icon widget
样例:文字对齐
下面的样例将会显示三次”Hey!”,但是使用不同的字体和不同颜色。特别指定  Row  的  crossAxisAlignment  和  textBaseline  属性。
1. 点击 运行 按钮。
2. 将  CrossAxisAlignment.center  改为  CrossAxisAlignment.baseline然后再次运行。
Icon  Widget 能够显示图形符号,这代表了 UI 的一个方面。Flutter 将会为 Material 和 Cupertino 的应用提前加载 icon packages。
样例:创建一个 Icon
下面的样例显示了来自 Material Icon library 的红蓝  Icons.widget  Widget。
1. 点击 运行 按钮。
2.  添加另一个来自  Material Icon library  的  Icon  并将其大小设为 50。
3. 给  Icon  何止一个来自  Material Color palette  的  Colors.amber  色,然后再次运行。
9. Image widget
Image  widget 显示了一张图片。你还能够直接引用图片 URL,或是你的应用 package 中的图片。但是由于 DartPad 无法引用包图片,所以下面的样例将会使用网络上的图片。
样例:显示一张图片
下面的样例将会显示一张储存在远端 GitHub 上的图片。  Image.network  方法接收一个含有图片 url 的字符串。
在这个样例中, Image.network  包含了一个短小的 URL。
1. 点击 运行 按钮。
2.  将短 URL 替换为实际 URL:
https://github.com/flutter/website/blob/master/examples/layout/sizing/images/pic3.jpg?raw=true
3. 然后将  pic3.jpg  改为  pic1.jpg  或  pic2.jpg ,然后重新运行。
10. 综合练习
你就要完成这个 codelab 了!如果你想要检验你刚学的知识,为何不讲这些结合起来,构建一个显示名片的 Flutter UI 呢!
Flutter 布局基础教程_第1张图片
你将会把 Flutter 的布局分解成几个部分,这就是如何在实际开发中构建 Flutter UI 方式!
在第一部分, 你将会实现包含姓名和标题的  Column 。然后你将会在  Column  包裹一个含有 icon 的  Row ,它将会被放在姓名和标题的左边。
Flutter 布局基础教程_第2张图片
在第二部分中,你将会在  Row  外包裹一个  Column ,所以你的代码中就包含了一个 Column(Row(Column))。然后你将调整最外面的 Column 的布局,所以它看起来不错。最后,您将添加联系信息到最外面的 Column 的 children 中,所以它将显示在名称,标题和图标下方。
Flutter 布局基础教程_第3张图片
在第三部分,你将会完成添加了更多图标的名片,它们会被放在联系信息的下方。
Flutter 布局基础教程_第4张图片
第一部分
练习:创建 name 和 title
实现含有两个 Text Widget 的  Column
  • 第一个  Text  widget 有一个叫做  Flutter McFlutter  的名字,并将其  style  属性设为  Theme.of(context).textTheme.headline
  • 第二个  Text  widget 包含了标题  Experienced Dev elope r
对于这个  Column ,将其  mainAxisSize  设为  MainAxisSize.min ,  crossAxisAlignment  设为  CrossAxisAlignment.start
练习:在 Column 外包裹一个 Row
你将在下面的 Widgets 中实现  Row  包裹一个  Column :ßß
  • 将一个  Icon  widget 设为 Icons.account_circle ,并设为 50 像素大小。
  • 在  Icon  widget 外包裹一个  Padding  widget 以在其周围创建  match 8 像素的空间。为了完成这个,你可以指定其 match    padding  属性为  const EdgeInsets.all(8.0) match 这个  Row  看上去会像这样:

     Row(	

       children: [	

        Padding(	

          padding: const EdgeInsets.all(8.0),	

          child: Icon(Icons.account_circle, size: 50),	

        ),	

        Column( ... ), // <--- The Column you first implemented	

      ],	

     );
第二部分
练习:调整布局
将  Column  包裹在  Row  外面,并将其  mainAxisSize  属性设为  MainAxisSize.min ,  crossAxisAlignment  属性设为  CrossAxisAlignment.stretch 。这个  Column  将包含以下 widgets:
  • 一个高度为 8 的  SizedBox  widget。
  • 一个空的  Row ,你等会将用它来添加联系方式。
  • 第二个高度为 16 的  SizedBox  widget。
  • 第二个空的  Row ,你将会添加四个图标。(第三部分)
Column  Widget 的列表格式应该如下一样,联系信息和图标显示在名称和头衔下方:
],
    ), // <--- Closing parenthesis for the Row
    SizedBox(),
    Row(), // First empty Row
    SizedBox(),
    Row(), // Second empty Row
   ],
  ); // <--- Closing parenthesis for the Column that wraps the Row
练习:输入联系信息
在第一个空的  Row  中,添加两个  Text  widget。
  • 第一个  Text  widget 包含了  123 Main Street  的地址。
  • 第二个  Text  widget 包含了电话号 (415) 555-0198
对于第一个空的  Row ,将  mainAxisAlignment  属性设为  MainAxisAlignment.spaceBetween
第三部分
练习:添加四个图标
在第二个空的  Row  中添加以下四个  Icon  widget。
  • Icons.accessibility
  • Icons.timer
  • Icons.phone_android
  • Icons.phone_iphone
对于第二个空的  Row ,将其  mainAxisAlignment  属性设为  MainAxisAlignment.spaceAround
11. 下一步是什么?

恭喜你,已经完成了这个 codelab!如果你想要了解关于 Flutter 的更多信息,这里有些值得探索的资源要推荐给你:
  • 查看 sample apps。
  • 访问 Flutter’s YouTube channel,你将能够观看大量专注于独立的 widget 以及开发者如何构建应用的视频。

你可能感兴趣的:(Flutter 布局基础教程)