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: [
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: [Card()],
),
让我们分析这段代码。网格视图调用 count()
构造函数,因要添加的项目数是可数的而不是无限的。但它需要更多信息来定义其布局。
crossAxisCount:
指定横向显示数目,我们设置成 2 列。
Flutter 中的 Cross axis(横轴) 表示非滚动轴。可滚动的方向称为 主轴。所以如果你的应用像网格视图默认的那样垂直滚动,那么横轴就是水平方向。
详情请参阅构建布局。
padding:
字段为网格视图的 4 条边设置填充。当然你现在看不到首尾的填充,因为网格视图内还没有其他子项。
childAspectRatio:
字段依据宽高比确定其大小。
默认地,网格视图中的项目尺寸相同。
将这些加在一起,网格视图按照如下方式计算每个子项的宽度:([整个网格宽度] - [左填充] - [右填充]) / 列数
。在这里就是:([整个网格宽度] - 16 - 16) / 2
。
高度是根据宽度计算得来的,通过应用宽高比:([整个网格宽度] - 16 - 16) / 2 * 9 / 8
。我们翻转了 8 和 9,因为我们是用宽度来计算高度。
我们已经有了一个空的卡片了,让我们添加一些子部件到卡片中。
布局内容
卡片内应该包含一张图片、一个标题和一个次级文本。
更新网格视图的子项:
// TODO: 构建一组卡片(102)
children: [
Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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: [
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 _buildGridCards(int count) {
List cards = List.generate(
count,
(int index) => Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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: [
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 _buildGridCards(BuildContext context) {
List products = ProductsRepository.loadProducts(Category.all);
if (products == null || products.isEmpty) {
return const [];
}
final ThemeData theme = Theme.of(context);
final NumberFormat formatter = NumberFormat.simpleCurrency(
locale: Localizations.localeOf(context).toString());
return products.map((product) {
return Card(
// TODO: 调整卡片高度(103)
最后
总而言之,Android开发行业变化太快,作为技术人员就要保持终生学习的态度,让学习力成为核心竞争力,所谓“活到老学到老”只有不断的学习,不断的提升自己,才能跟紧行业的步伐,才能不被时代所淘汰。
在这里我分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司20年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
能跟紧行业的步伐,才能不被时代所淘汰。
在这里我分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司20年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
[外链图片转存中…(img-yDoRWZRN-1715604697369)]
[外链图片转存中…(img-B5ElYnZo-1715604697371)]
[外链图片转存中…(img-7r1ECXIG-1715604697373)]
还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!