欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

[译] MDC-102 Flutter:Material 结构和布局(Flutter)

发布时间:2023/12/10 69 豆豆
生活随笔 收集整理的这篇文章主要介绍了 [译] MDC-102 Flutter:Material 结构和布局(Flutter) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.
  • 原文地址:MDC-102 Flutter: Material Structure and Layout (Flutter)
  • 原文作者:codelabs.developers.google.com
  • 译文出自:掘金翻译计划
  • 本文永久链接:github.com/xitu/gold-m…
  • 译者:DevMcryYu
  • 校对者:Rickon

MDC-102 Flutter:Material 结构和布局(Flutter)

1. 介绍

Material Components(MDC)帮助开发者实现 Material Design。MDC 由谷歌团队的工程师和 UX 设计师创造,为 Android、iOS、Web 和 Flutter 提供很多美观实用的 UI 组件。

material.io/develop

在教程 MDC-101 中,你使用了两个 Material 组件:文本框和墨水波纹效果的按钮来构建一个登陆页面。现在让我们通过添加导航、结构和数据来拓展应用。

你将要构建

在本教程中,你将为 Shrine —— 一个销售服装和家居用品的电子商务应用程序构建一个主页面。它将含有:

  • 一个位于顶部的应用栏
  • 一个由产品填充的网格列表

这是四篇教程里的第二篇,它将引导你为 Shrine 的产品构建应用程序。我们建议你按照教程的顺序一步一步地编写你的代码。

相关的教程可以在以下位置找到:

  • MDC-101: Material Components(MDC)基础
  • MDC-103: Material Design Theming 的颜色、形状、高度和类型
  • MDC-104: Material Design 高级组件。

到 MDC-104 的最后,你将会构建一个像这样的应用:

将要用到的 MDC 组件

  • 顶部应用栏(Top app bar)
  • 网格(Grid)
  • 卡片(Card)

本教程中,你将使用 MDC-Flutter 提供的默认组件。你将会在 MDC-103: Material Design Theming 的颜色、形状、高度和类型中学习如何定制它们。

你将需要

  • Flutter SDK
  • 安装好 Flutter 插件的 Android Studio,或者你喜欢的代码编辑器
  • 示例代码

要在 iOS 上构建和运行 Flutter 应用程序,你需要满足以下要求:

  • 运行 macOS 的计算机
  • Xcode 9 或更新版本
  • iOS 模拟器,或者 iOS 物理设备

要在 Android 上构建和运行 Flutter 应用程序,你需要满足以下要求:

  • 运行 macOS、Windows 或 Linux 的计算机
  • Android Studio
  • Android 模拟器(随 Android Studio 一起提供)或 Android 物理设备

2. 安装 Flutter 环境

前提条件

要开始使用 Flutter 开发移动应用程序,你需要:

  • Flutter SDK
  • 装有 Flutter 插件的 IntelliJ IDE,或者你喜欢的代码编辑器

Flutter 的 IDE 工具适用于 Android Studio、IntelliJ IDEA Community(免费)和 IntelliJ IDEA Ultimate。

要在 iOS 上构建和运行 Flutter 应用程序,你需要满足以下要求:

  • 运行 macOS 的计算机
  • Xcode 9 或更新版本
  • iOS 模拟器,或者 iOS 物理设备

要在 Android 上构建和运行 Flutter 应用程序,你需要满足以下要求:

  • 运行 macOS、Windows 或者 Linux 的计算机
  • Android Studio
  • Android 模拟器(随 Android Studio 一起提供)或 Android 物理设备

获取详细的 Flutter 安装信息

重要提示:如果连接到计算机的 Android 手机上出现“允许 USB 调试”对话框,请启用始终允许从此计算机选项,然后单击确定

在继续本教程之前,请确保你的 SDK 处于正确的状态。如果之前安装过 Flutter,则使用 flutter upgrade 来确保 SDK 处于最新版本。

flutter upgrade 复制代码

运行 flutter upgrade 将自动运行 flutter doctor。如果这是首次安装 Flutter 且不需升级,那么请手动运行 flutter doctor。查看显示的所有检查标记;这将会下载你需要的任何缺少的 SDK 文件,并确保你的计算机配置无误以进行 Flutter 的开发。

flutter doctor 复制代码

3. 下载教程初始应用程序

从 MDC-101 继续?

如果你完成了 MDC-101,那么本教程所需代码应该已经准备就绪,跳转到 添加应用栏 步骤。

从头开始?

下载初始应用程序

下载初始程序

此入门程序位于 material-components-flutter-codelabs-102-starter_and_101-complete/mdc_100_series 目录中。

...或者从 GitHub 克隆它

要从 GitHub 克隆此项目,请运行以下命令:

git clone https://github.com/material-components/material-components-flutter-codelabs.git cd material-components-flutter-codelabs git checkout 102-starter_and_101-complete 复制代码

更多帮助:从 GitHub 上克隆存储库

正确的分支

教程 MDC-101 到 104 连续构建。所以当你完成 102 的代码后,它将变成 103 教程的初始代码!代码被分成不同的分支,你可以使用以下命令将它们全部列出:

git branch --list

要查看完整代码,请切换到 103-starter_and_102-complete 分支。

建立你的项目

以下步骤默认你使用的是 Android Studio (IntelliJ)。

创建项目

  • 在终端中,导航到 material-components-flutter-codelabs

  • 运行 flutter create mdc_100_series

  • 打开项目

  • 打开 Android Studio。

  • 如果你看到欢迎页面,单击 打开已有的 Android Studio 项目

  • 导航到 material-components-flutter-codelabs/mdc_100_series 目录并单击打开,这将打开此项目。
  • 在构建项目一次之前,你可以忽略在分析中见到的任何错误。

  • 在左侧的项目面板中,删除测试文件 ../test/widget_test.dart
  • 如果出现提示,安装所有平台和插件更新或 FlutterRunConfigurationType,然后重新启动 Android Studio。
  • 提示:确保你已安装 Flutter 和 Dart 插件。

    运行初始程序

    以下步骤默认你在 Android 模拟器或设备上进行测试。你也可以在 iOS 模拟器或设备上进行,只要你安装了 Xcode。

  • 选择设备或模拟器
  • 如果 Android 模拟器尚未运行,请选择 Tools -> Android -> AVD Manager 来创建您设备并启动模拟器。如果 AVD 已存在,你可以直接在 IntelliJ 的设备选择器中启动模拟器,如下一步所示。

    (对于 iOS 模拟器,如果它尚未运行,通过选择 Flutter Device Selection -> Open iOS Simulator 来在你的开发设备上启动它。)

  • 启动 Flutter 应用:
    • 在你的编辑器窗口顶部寻找 Flutter Device Selection 下拉菜单,然后选择设备(例如,iPhone SE / Android SDK built for )。
    • 点击运行图标()。

    如果你无法成功运行此应用程序,停下来解决你的开发环境问题。尝试导航到 material-components-flutter-codelabs;如果你在终端中下载 .zip 文件,导航到 material-components-flutter-codelabs-... 然后运行 flutter create mdc_100_series。

    成功!Shrine 的初始登陆代码应该在你的模拟器中运行了。你可以看到 Shrine 的 logo 和它下面的名称 "Shrine"。

    现在登录页面看起来不错,让我们用一些产品来填充应用。

    4. 添加顶部应用栏

    当登陆页面消失时主页面将出现并显示“你做到了!”。这很棒!但是我们的用户不知道能做什么操作,也不知道现在位于应用何处,为了解决这个问题,是时候添加导航了。

    导航 是指允许用户在应用中移动的组件、交互、视觉提示和信息结构。它使得内容和功能更加注目,任务也因此易于完成。

    在 Material 指南中了解更多有关导航的信息。

    Material Design 提供确保高度可用性的导航模式,其中最注目的组件就是顶部应用栏。

    你可以将顶部应用栏当作 iOS 中的“导航栏”,或者简单看成一个 “App Bar” 或 “Header”。

    要提供导航并让用户快速访问其他操作,让我们添加一个顶部应用栏。

    添加应用栏部件

    在 home.dart 中,将应用栏添加到 Scaffold 中:

    return Scaffold(// TODO: 添加应用栏(102)appBar: AppBar(// TODO: 添加按钮和标题(102)), 复制代码

    AppBar 添加到 Scaffold 的 appBar: 字段位置,为了我们完美的布局,让应用栏保持在页面的顶部或底部。

    Scaffold 在中是一个重要的部件。它为像抽屉、snack bar 和 bottom sheet 等各种常见 Material 组件提供方便的 API。它甚至可以帮助布置一个 Floating Action Button。

    在 Flutter 文档中了解更多有关 Scaffold 的信息。

    保存项目,当 Shrine 应用更新后,单击 Next 来查看主屏幕。

    应用栏看起来不错,但它还需要一个标题。

    如果应用没有更新,再次单击 “Play” 按钮,或者点击 “Play” 后的 “Stop”。

    添加文本部件

    在 home.dart 中,给应用栏添加一个标题:

    // TODO: 添加应用栏(102) appBar: AppBar(// TODO: 添加按钮和标题(102)title: Text('SHRINE'),// TODO:添加后续按钮(102) 复制代码

    保存项目。

    到目前为止,你应该已经注意到我们所说的“平台差异”了。Material 明白 Android、iOS、Web 各平台都有差异。用户对他们有不同的期望。举例来说,在 iOS 里标题几乎总是居中的,这是 UIKit 提供的默认配置。在 Android 上标题是左对齐的。所以如果你使用的是 Android 模拟器或设备,那么标题应该位于左侧,对于 iOS 模拟器和设备而言,它应该是居中的。

    了解更多信息,请查参阅有关跨平台适配的 Material 文章。

    许多应用栏在标题旁边都设有按钮,让我们在应用中添加一个菜单图标。

    添加位于首部的图标按钮

    还是在 home.dart 中,在 AppBar 的 leading 字段设置一个图标按钮:(放在 title: 字段前,按照部件从首到尾的顺序):

    return Scaffold(appBar: AppBar(// TODO: 添加按钮和标题(102)leading: IconButton(icon: Icon(Icons.menu,semanticLabel: 'menu',),onPressed: () {print('Menu button');},), 复制代码

    保存项目。

    菜单图标(也被称作“汉堡包”)会在你期望的位置显示出来。

    IconButton 类是在你的应用里引入 Material 图标的快捷方式。它有一个 Icon 部件。 Flutter 在 Icons 类里有整套的图标。它会根据字符串常量的映射自动导入图标。

    在 Flutter 文档中了解更多有关 Icons 类的信息。有关 Icon 部件的信息请阅读这个 Flutter 文档。

    你也可以在标题尾部添加按钮。在 Flutter 中,它们被称为 "action"。

    Leading(首部)trailing(尾部) 是表达方向的术语,指的是与语言无关的文本行的开头和结尾。当使用一个像英语这样的 LTR(左到右)语言时, leading 意味着 左侧 而 trailing 代表着 右侧。在像阿拉伯语这样的 RTL(右到左)语言时, leading 意味着 右侧 而 trailing 代表着 左侧

    了解 UI 镜像的更多信息,请参阅 双向性 Material Design 准则。

    添加 action

    还有两个 IconButton 的空间。

    在 AppBar 实例中的标题后面添加它们:

    // TODO: 添加尾部按钮(102) actions: <Widget>[IconButton(icon: Icon(Icons.search,semanticLabel: 'search',),onPressed: () {print('Search button');},),IconButton(icon: Icon(Icons.tune,semanticLabel: 'filter',),onPressed: () {print('Filter button');},), ], 复制代码

    保存你的项目。你的主屏幕看起来应该像这样:

    现在这个应用在左侧有一个按钮、一个标题,右侧还有两个 action。应用栏还利用阴影显示高度,表示它与内容处于不同的层级。

    在 Icon 类中,SemanticLabel 字段是在 Flutter 中添加辅助功能信息的常用方法。这很像 Android 的 Content Label 或 iOS 的 UIAccessibility accessibilityLabel。你会在很多类中见到它。

    这个字段的信息很好地向使用屏幕阅读器的人说明了该按钮的作用。

    对于没有 semanticLabel: 字段的部件,你可以将其包装在 Semantics 部件中,在其 Flutter 文档中了解更多有关的信息。

    5. 在网格中添加卡片

    现在我们的应用像点样子了,让我们接着放置一些卡片来组织内容。

    卡片 是显示单体内容和动作的独立的元素。它们是一种可以灵活地呈现近似内容集合的方式。

    在 Material 指南有关卡片的文章中了解更多信息。

    要了解卡片部件,请参阅在 Flutter 中构建布局。

    添加网格视图

    让我们从应用栏底部添加一个卡片开始。单一的 卡片 部件不足以让我们将它放到我们想要的位置,所以我们需要将它封装在一个 网格视图 中。

    用 GridView 替换 Scaffold 中 body 字段的 Center:

    // TODO: 添加网格视图(102) body: GridView.count(crossAxisCount: 2,padding: EdgeInsets.all(16.0),childAspectRatio: 8.0 / 9.0,// TODO: 构建一组卡片(102)children: <Widget>[Card()], ), 复制代码

    让我们分析这段代码。网格视图调用 count() 构造函数,因要添加的项目数是可数的而不是无限的。但它需要更多信息来定义其布局。

    crossAxisCount: 指定横向显示数目,我们设置成 2 列。

    Flutter 中的 Cross axis(横轴) 表示非滚动轴。可滚动的方向称为 主轴。所以如果你的应用像网格视图默认的那样垂直滚动,那么横轴就是水平方向。

    详情请参阅构建布局。

    padding: 字段为网格视图的 4 条边设置填充。当然你现在看不到首尾的填充,因为网格视图内还没有其他子项。

    childAspectRatio: 字段依据宽高比确定其大小。

    默认地,网格视图中的项目尺寸相同。

    将这些加在一起,网格视图按照如下方式计算每个子项的宽度:([整个网格宽度] - [左填充] - [右填充]) / 列数。在这里就是:([整个网格宽度] - 16 - 16) / 2。

    高度是根据宽度计算得来的,通过应用宽高比:([整个网格宽度] - 16 - 16) / 2 * 9 / 8。我们翻转了 8 和 9,因为我们是用宽度来计算高度。

    我们已经有了一个空的卡片了,让我们添加一些子部件到卡片中。

    布局内容

    卡片内应该包含一张图片、一个标题和一个次级文本。

    更新网格视图的子项:

    // TODO: 构建一组卡片(102) children: <Widget>[Card(child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[AspectRatio(aspectRatio: 18.0 / 11.0,child: Image.asset('assets/diamond.png'),),Padding(padding: EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[Text('Title'),SizedBox(height: 8.0),Text('Secondary Text'),],),),],),) ], 复制代码

    这段代码添加了一个列部件,用来垂直地布局子部件。

    crossAxisAlignment: 字段指定 CrossAxisAlignment.start 属性,这意味着“文本与前沿对齐”。

    AspectRatio 部件决定图像的形状,无论提供的是何种图像。

    Padding 使得文本与边框保持一定距离。

    两个 Text 部件垂直堆叠,在其间保持 8 个单位的间隔(SizedBox)。我们使用另一个 Column 来把它们放到 Padding 中。

    保存你的项目:

    在这个预览里,你可以看到卡片从边缘置入,并带有圆角和阴影(这代表着卡片的高度)。整个形状在 Material 中被称为 “container(容器)”。(不要与名为 Container 的实际部件类混淆。)

    除了容器以外,在 Material 中卡片内所有的元素实际上都是可选的。你可以添加标题文本、缩略图、头像或者小标题文本、分隔符甚至是按钮和图标。

    了解更多消息,请参阅 Material 指南上有关卡片的文章。

    卡片经常以集合的形式和其他卡片一起出现,让我们在网格视图中给它们布局。

    6. 生成卡片集合

    每当屏幕上出现多张卡片时,它们就会组成一个或多个集合。集合中的卡片是共面的,这意味着卡片共享相同的静止高度。(除了卡片被拾起或拖动,但在这里我们不会这么做。)

    将卡片添加到集合

    现在我们的卡片是网格视图内的 children: 字段子项。这有一大段难以阅读的嵌套代码。让我们将它提取到一个函数中来生成任意数量的空卡片,然后返回给我们。

    // TODO: 生成卡片集合(102) List<Card> _buildGridCards(int count) {List<Card> cards = List.generate(count,(int index) => Card(child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[AspectRatio(aspectRatio: 18.0 / 11.0,child: Image.asset('assets/diamond.png'),),Padding(padding: EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[Text('Title'),SizedBox(height: 8.0),Text('Secondary Text'),],),),],),),);return cards; } 复制代码

    将生成的卡片分配给网格视图的 children 字段。记得用新代码替换网格视图中的所有内容。

    // TODO: 添加网格视图(102) body: GridView.count(crossAxisCount: 2,padding: EdgeInsets.all(16.0),childAspectRatio: 8.0 / 9.0,children: _buildGridCards(10) // 替换所有内容 ), 复制代码

    保存你的项目:

    卡片已经在这了,但它们什么都没有显示。现在是时候添加一些产品数据了。

    ###添加产品数据

    这个应用中的产品有着图像、名称和价格。让我们把这些添加到已有的卡片部件中。

    然后,在 home.dart 中,导入数据模型需要的新包和文件:

    import 'package:flutter/material.dart'; import 'package:intl/intl.dart';import 'model/products_repository.dart'; import 'model/product.dart'; 复制代码

    最后,更改 _buildGridCards() 来获取产品信息,并将数据应用到卡片中:

    // TODO: 生成卡片集合(102)// 替换整个方法 List<Card> _buildGridCards(BuildContext context) {List<Product> products = ProductsRepository.loadProducts(Category.all);if (products == null || products.isEmpty) {return const <Card>[];}final ThemeData theme = Theme.of(context);final NumberFormat formatter = NumberFormat.simpleCurrency(locale: Localizations.localeOf(context).toString());return products.map((product) {return Card(// TODO: 调整卡片高度(103)child: Column(// TODO: 卡片的内容设置居中(103)crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[AspectRatio(aspectRatio: 18 / 11,child: Image.asset(product.assetName,package: product.assetPackage,// TODO: 调整盒子尺寸(102)),),Expanded(child: Padding(padding: EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),child: Column(// TODO: 标签底部对齐并居中(103)crossAxisAlignment: CrossAxisAlignment.start,// TODO: 更改最内部的列(103)children: <Widget>[// TODO: 处理溢出的标签(103)Text(product.name,style: theme.textTheme.title,maxLines: 1,),SizedBox(height: 8.0),Text(formatter.format(product.price),style: theme.textTheme.body2,),],),),),],),);}).toList(); } 复制代码

    注意:应用现在无法编译和运行,我们还需要进行修改。

    要设置文本的样式,我们使用当前 BuildContext 中的 ThemeData

    了解有关文本样式的更多信息,请参阅 Material 指南中的排版一文。了解有关主题的更多信息,请参考教程下一章 MDC-103: Material Design Theming 的颜色、形状、高度和类型。

    在尝试编译之前,将 BuildContext 传入 build() 方法中的 _buildGridCards():

    // TODO: Add a grid view (102) body: GridView.count(crossAxisCount: 2,padding: EdgeInsets.all(16.0),childAspectRatio: 8.0 / 9.0,children: _buildGridCards(context) // Changed code ), 复制代码

    你可能注意到了我们没有在卡片间添加任何垂直的间隔,这是因为在其顶部与底部默认有 4 个单位的填充。

    保存你的项目:

    产品的数据显示出来了,但是图像四周有额外的空间。图像默认依据 .scaleDown 的 BoxFit 绘制(在这个情况下)。让我们将其更改为 .fitWidth 来让它们放大一点,删除多余的空间。

    修改图像的 fit: 字段:

    // TODO: 调整盒子尺寸(102)fit: BoxFit.fitWidth, 复制代码

    现在我们的产品完美的展现在应用中了!

    7. 总结

    我们的应用已经有了基本的流程,将用户从登陆屏幕带到可以查看产品的主屏幕。通过几行代码,我们添加了一个顶部应用栏(带有标题和三个按钮)以及卡片(用于显示我们应用的内容)。我们的主屏幕简洁实用,具有基本的结构和可操作的内容。

    完成的 MDC-102 应用可以在 103-starter_and_102-complete 分支中找到。

    你可以用此分支下的应用来对照验证你的版本。

    下一步

    通过顶部应用栏、卡片、文本框和按钮,我们已经使用了 MDC-Flutter 库中的四个核心组件!你可以访问 Flutter 部件目录来探索更多组件。

    虽然它完全正常运行,我们的应用尚未表达任何特殊的品牌特点。在 MDC-103: Material Design Theming 的颜色、形状、高度和类型中,我们将定制这些组件的样式,来诠释一个充满活力的、现代的品牌。

    如果发现译文存在错误或其他需要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 本文永久链接 即为本文在 GitHub 上的 MarkDown 链接。


    掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。

    总结

    以上是生活随笔为你收集整理的[译] MDC-102 Flutter:Material 结构和布局(Flutter)的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。