MDC-103 Flutter:通过颜色、形状、高度和类型设置 Material 主题 (Flutter)

logo_components_color_2x_web_96dp.png

Material 组件 (MDC) 有助于开发者实现 Material Design。MDC 是由 Google 的一组工程师和用户体验设计师创建的,包含数十种精美实用的界面组件,可用于 Android、iOS、网页和 Flutter。如需了解详情,请访问 material.io/develop

现在,您可以比以往更多地使用 MDC 自定义应用的独特样式。Material Design 的近期扩展可让设计师和开发者更灵活地表达其产品的品牌。

在 Codelab MDC-101 和 MDC-102 中,您使用 Material 组件 (MDC) 构建了一款名为 Shrine 的应用的基础内容,这是一款销售服装和家居用品的电子商务应用。该应用包含的用户流从登录屏幕开始,然后将用户转到显示产品的主屏幕。

构建内容

在此 Codelab 中,您将利用以下各项自定义 Shrine 应用:

  • 颜色
  • 字体排版
  • 高度
  • 形状
  • 布局

7f521db8a762f5ee.png 7ac46e5cb6b1e064.png

此 Codelab 中的 MDC-Flutter 组件和子系统

  • 主题
  • 字体排版
  • 高度
  • 图片列表

您在 Flutter 开发方面的经验处于什么水平?

新手 中级 熟练

前期准备

想要开始使用 Flutter 开发移动应用,您需要:

  1. 下载并安装 Flutter SDK。
  2. 使用 Flutter SDK 更新您的 PATH。
  3. 安装带有 Flutter 和 Dart 插件的 Android Studio 或您喜欢使用的编辑器。
  4. 安装 Android 模拟器、iOS 模拟器(需要装有 Xcode 的 Mac)或使用实体设备。

如需 Flutter 安装方面的更多信息,请参阅使用入门:安装。如需设置编辑器,请参阅使用入门:设置编辑器。安装 Android 模拟器时,您可以随意使用默认选项,例如带有最新系统映像的 Pixel 3 手机。建议启用虚拟机加速功能,但这并非强制要求。完成上述 4 个步骤后,您可以返回到此 Codelab。如需完成此 Codelab,您只需要安装适用于一个平台(Android 或 iOS)的 Flutter。

确保 Flutter SDK 的版本符合要求

在继续学习此 Codelab 之前,请确保您的 SDK 版本符合要求。如果 Flutter SDK 是之前安装的,请使用 flutter upgrade 确保 SDK 是最新版本。

 flutter upgrade

运行 flutter upgrade 时系统会自动运行 flutter doctor.如果这是新安装的 Flutter,并且没有必要升级,那么请手动运行 flutter doctor。它将报告是否存在为了完成设置而需要安装的任何依赖项。您尽可忽略对您来说无关的对勾标记(例如,如果您不打算针对 iOS 进行开发,则可以忽略 Xcode)。

 flutter doctor

常见问题解答

接续 MDC-102?

如果您已完成 MDC-102,您的代码应该可以直接用于此 Codelab。请跳到以下步骤:更改颜色。

从头开始?

下载起始 Codelab 应用

下载起始应用

起始应用位于 material-components-flutter-codelabs-103-starter_and_102-complete/mdc_100_series 目录中。

…或从 GitHub 克隆

如需从 GitHub 克隆此 Codelab,请运行以下命令:

git clone https://github.com/material-components/material-components-flutter-codelabs.git
cd material-components-flutter-codelabs/mdc_100_series
git checkout 103-starter_and_102-complete

设置您的项目

以下说明假定您使用的是 Android Studio (IntelliJ)。

打开项目

1. 打开 Android Studio。

2. 如果您看到欢迎屏幕,请点击 Open an existing Android Studio project

3. 转到 material-components-flutter-codelabs/mdc_100_series 目录并点击“Open”。此时项目应会打开。您可以忽略在 Dart Analysis 中看到的任何错误,直到您已构建了一次项目。

4. 如果出现提示,请执行以下操作:

  • 安装所有的平台和插件更新或 FlutterRunConfigurationType。
  • 如果未配置 Dart 或 Flutter SDK,请设置 Flutter 插件的 Flutter SDK 路径
  • 配置 Android 框架。
  • 点击“Get dependencies”或“Run ‘flutter packages get'”。

然后,重启 Android Studio。

运行起始应用

以下说明假定您在 Android 模拟器或设备上进行测试,但如果您已安装 Xcode,也可以在 iOS 模拟器或设备上进行测试。

1. 选择设备或模拟器。如果 Android 模拟器尚未运行,请依次选择 Tools -> Android -> AVD Manager,以创建虚拟设备并启动模拟器。如果 AVD 已存在,您可以直接从 Android Studio 中的设备选择器启动模拟器,如下一步所示。(对于 iOS 模拟器,如果它尚未运行,请依次选择 Flutter Device Selection -> Open iOS Simulator,在开发机器上启动模拟器。)

2. 启动您的 Flutter 应用:

  • 查看编辑器屏幕顶部的“Flutter Device Selection”下拉菜单,然后选择设备(例如,针对 <version> 构建的 iPhone SE 或 Android SDK)。
  • Play 图标 ()。

大功告成!您应该会在模拟器中看到之前的 Codelab 中的 Shrine 登录页面。

Android

iOS

点击“Next”可查看上一个 Codelab 中的首页。

Android

iOS

设计师已创建代表 Shrine 品牌的配色方案,并希望您在 Shrine 应用中实现该配色方案

首先,我们要将这些颜色导入到项目中。

创建 colors.dart

lib 中,新建一个名为 colors.dart 的 dart 文件。导入 Material 组件并添加 const 颜色值:

import 'package:flutter/material.dart';

const kShrinePink50 = Color(0xFFFEEAE6);
const kShrinePink100 = Color(0xFFFEDBD0);
const kShrinePink300 = Color(0xFFFBB8AC);
const kShrinePink400 = Color(0xFFEAA4A4);

const kShrineBrown900 = Color(0xFF442B2D);

const kShrineErrorRed = Color(0xFFC5032B);

const kShrineSurfaceWhite = Color(0xFFFFFBFA);
const kShrineBackgroundWhite = Colors.white;

自定义调色板

此颜色主题已由设计师使用自定义颜色创建好(如下图所示)。它包含从 Shrine 品牌中选择的颜色,并且这些颜色已应用到 Material Theme Editor,而该编辑器对它们进行了扩展,形成了颜色更丰富的调色板。(这些颜色并非来自 2014 Material 调色板。)

Material Theme Editor 已经按照不同深浅整理这些颜色并以数字标签对其进行标记,每种颜色都包括以下标签:50、100、200…一直到 900。Shrine 只使用粉色色样中深浅为 50、100 和 300 的颜色和棕色色样中深浅为 900 的颜色。

wlq5aH94SfU47pcalUqOSK57OCX4HnJJTpMVzVrBZreUOE-CrkX2akKrnTbgwf6BQNMBi-nn16jpgQHDeQZixTCeh1A0qTXcxDMTcc2-e6uJg0LPjkXWEVlV7cwS0U1naqpnHToEIQ 1HLdzGp-TIhg2ULijquMw_KQdk18b080CVQN_oECAhiCnFI11Nm3nbcsCIXvZBXULMajAW9NEmGZ7iR_j-eEF6NiODuaike96xVpLwUIzfV4dzTg9uQHsmNG-BDTOd04e6_eRLs--Q

微件的每个带颜色参数都会映射到这些方案中的一种颜色。例如,文本字段在主动接收输入内容时,它的装饰的颜色应为主题的主色。如果该颜色不易辨认(在所处背景下难以辨别),请改用 PrimaryVariant。

这些变体是针对 2014 年推出的《Material 准则》创建的,并且仍在当前准则(请参阅“颜色系统”一文)和 MDC-Flutter 中提供。如需在代码中使用这些变体,只需调用基本颜色,然后调用颜色深浅(其值通常是 100 的倍数)。例如,Pink 400 可通过以下命令检索:Colors.pink[400]

这些调色板完全可以用于您的设计和代码。如果您已经有了品牌专用色,那么您可以使用调色板生成工具Material Theme Editor 自行生成颜色和谐的调色板。

现在,我们已经有了想要使用的颜色,可以将其应用于界面了。为此,我们将在微件层次结构的顶部,设置应用到 MaterialApp 实例的 ThemeData 微件的值。

自定义 ThemeData.light()

Flutter 包含几个内置主题。浅色主题就是其中之一。接下来,我们就要复制浅色主题,并更改相应的值以针对我们的应用进行自定义,而不是从头开始构建 ThemeData 微件。

colors.dart 导入到 app.dart.

import 'colors.dart';

然后,将以下代码添加到 app.dart 中 ShrineApp 类的范围之外:

// TODO: Build a Shrine Theme (103)
final ThemeData _kShrineTheme = _buildShrineTheme();

ThemeData _buildShrineTheme() {
  final ThemeData base = ThemeData.light();
  return base.copyWith(
    accentColor: kShrineBrown900,
    primaryColor: kShrinePink100,
    buttonTheme: base.buttonTheme.copyWith(
      buttonColor: kShrinePink100,
      colorScheme: base.colorScheme.copyWith(
        secondary: kShrineBrown900,
      ),
    ),
    buttonBarTheme: base.buttonBarTheme.copyWith(
      buttonTextTheme: ButtonTextTheme.accent,
    ),
    scaffoldBackgroundColor: kShrineBackgroundWhite,
    cardColor: kShrineBackgroundWhite,
    textSelectionColor: kShrinePink100,
    errorColor: kShrineErrorRed,
    // TODO: Add the text themes (103)
    // TODO: Add the icon themes (103)
    // TODO: Decorate the inputs (103)
  );
}

现在,将 ShrineApp 的 build() 函数(MaterialApp 微件中)末尾的 theme: 设为新主题:

  // TODO: Add a theme (103)
  theme: _kShrineTheme, // New code

点击“Play”按钮。现在,登录屏幕应如下所示:

Android

iOS

主屏幕应如下所示:

Android

iOS

除颜色更改外,设计师还向我们提供了要使用的特定字体排版。Flutter 的 ThemeData 包括 3 个文本主题。每个文本主题都是文本样式的集合,例如“大标题”和“标题”。我们将在应用中使用几种样式,并更改部分值。

自定义文本主题

为了将字体导入项目,必须将其添加到 pubspec.yaml 文件中。

在 pubspec.yaml 中,紧跟在 flutter: 标记之后添加以下代码:

  # TODO: Insert Fonts (103)
  fonts:
    - family: Rubik
      fonts:
        - asset: fonts/Rubik-Regular.ttf
        - asset: fonts/Rubik-Medium.ttf
          weight: 500

现在,您可以访问和使用 Rubik 字体了。

pubspec 文件问题排查

如果直接剪切并粘贴上述声明,运行 pub get 时可能会遇到错误。如果遇到错误,请先移除前导空白,然后使用 2 个空格的缩进以空格替换这些空白。(

fonts:

之前两个空格,

family: Rubik

之前四个空格,依此类推。)

如果看到“Mapping values are not allowed here”,请检查问题行的缩进及其上一行的缩进。

login.dart 中,更改 Column() 中的以下代码:

Column(
  children: <Widget>[
    Image.asset('assets/diamond.png'),
    SizedBox(height: 16.0),
    Text(
      'SHRINE',
      style: Theme.of(context).textTheme.headline5,
    ),
  ],
)

app.dart 中的 _buildShrineTheme() 之后,添加以下代码:

// TODO: Build a Shrine Text Theme (103)
TextTheme _buildShrineTextTheme(TextTheme base) {
  return base.copyWith(
    headline5: base.headline5.copyWith(
      fontWeight: FontWeight.w500,
    ),
    headline6: base.headline6.copyWith(
        fontSize: 18.0
    ),
    caption: base.caption.copyWith(
      fontWeight: FontWeight.w400,
      fontSize: 14.0,
    ),
    bodyText1: base.bodyText1.copyWith(
      fontWeight: FontWeight.w500,
      fontSize: 16.0,
    ),
  ).apply(
    fontFamily: 'Rubik',
    displayColor: kShrineBrown900,
    bodyColor: kShrineBrown900,
  );
}

这段代码获取 TextTheme 并更改了大标题、标题和图片说明的外观。

以这种方式应用 fontFamily 只会将更改应用到 copyWith() 中指定的字体排版缩放值(大标题、标题、图片说明)。

对某些字体,我们要设置自定义 fontWeight。FontWeight 微件的值都是 100 的倍数,十分方便。在字体中,w500(500 的粗细)通常是中等粗细的字体,w400 通常是标准粗细的字体。

使用新的文本主题

将以下主题添加到 _buildShrineTheme 中的 errorColor 后:

// TODO: Add the text themes (103)

textTheme: _buildShrineTextTheme(base.textTheme),
primaryTextTheme: _buildShrineTextTheme(base.primaryTextTheme),
accentTextTheme: _buildShrineTextTheme(base.accentTextTheme),

点击“Stop”按钮,然后点击“Play”按钮。

登录屏幕和主屏幕上的文本看起来不同:有些文本使用的是 Rubik 字体,还有些文本显示为棕色而不是黑色或白色。

Android

iOS

请注意,此时图标仍为白色。这是因为图标有单独的主题。

使用自定义的主图标主题

将以下代码添加到 _buildShrineTheme() 函数中:

    // TODO: Add the icon theme (103)
    primaryIconTheme: base.iconTheme.copyWith(
      color: kShrineBrown900
    ),

点击“Play”按钮。

Android

iOS

应用栏中的图标变成了棕色!

缩小文本

现在的标签有点大。

home.dart 中,更改最里面一列的 children:

// TODO: Change innermost Column (103)
children: <Widget>[
// TODO: Handle overflowing labels (103)

  Text(
    product == null ? '' : product.name,
    style: theme.textTheme.button,
    softWrap: false,
    overflow: TextOverflow.ellipsis,
    maxLines: 1,
  ),
  SizedBox(height: 4.0),
  Text(
    product == null ? '' : formatter.format(product.price),
    style: theme.textTheme.caption,
  ),
  // End new code
],

居中放置文本

我们需要将标签居中,并将文本与每张卡片的底部对齐,而不是与每张图片的底部对齐。

将标签移到主轴末端(底部)并将其更改为居中:

// TODO: Align labels to the bottom and center (103)

  mainAxisAlignment: MainAxisAlignment.end,
  crossAxisAlignment: CrossAxisAlignment.center,

保存项目。

Android

iOS

相差不远了,只是文本并未在卡片上居中。

更改父列的交叉轴对齐方式:

// TODO: Center items on the card (103)

    crossAxisAlignment: CrossAxisAlignment.center,

保存项目。现在,主屏幕应如下所示:

Android

iOS

看起来效果好多了。

设置文本字段的主题

您还可以使用 InputDecorationTheme 对文本字段设置装饰的主题。

app.dart_buildShrineTheme() 方法中,指定 inputDecorationTheme: 值:

// TODO: Decorate the inputs (103)
inputDecorationTheme: InputDecorationTheme(
  border: OutlineInputBorder(),
),

目前,文本字段有一个 filled 装饰。我们要将其移除。移除 filled 并指定 inputDecorationTheme 将为文本字段提供轮廓样式。

login.dart 中,移除 filled: true 值:

// Remove filled: true values (103)
TextField(
  controller: _usernameController,
  decoration: InputDecoration(
    // Removed filled: true
    labelText: 'Username',
  ),
),
SizedBox(height: 12.0),
TextField(
  controller: _passwordController,
  decoration: InputDecoration(
    // Removed filled: true
    labelText: 'Password',
  ),
  obscureText: true,
),

点击“Run”菜单下的“Flutter Hot Restart”按钮(以从头开始重启应用)。当“Username”字段处于活动状态(您正在其中进行键入)时,登录屏幕应如下所示:

Android

iOS

在文本字段中进行键入。此时,装饰和悬浮占位符均以主色渲染。不过,我们不太容易看出来。人在色彩对比度不够高的情况下难以区分像素,因此这些元素不易辨认。(如需了解详情,请参阅 Material 准则“颜色”一文中的“易于辨认的颜色”部分)。我们要在 inputDecorationTheme: 中指定 focusedBorder: 以替换文本字段的强调色,使其成为设计师在上述颜色主题中向我们提供的 PrimaryVariant。

app.dart 中的 inputDecorationTheme: 下,指定一个 focusedBorder:

// TODO: Decorate the inputs (103)
inputDecorationTheme: InputDecorationTheme(
  focusedBorder: OutlineInputBorder(
    borderSide: BorderSide(
      width: 2.0,
      color: kShrineBrown900,
    ),
  ),
  border: OutlineInputBorder(),
),

接下来,我们将更改两个文本字段的 labelStyle 属性,以设计师提供的颜色主题为标签着色。

login.dart 中两个 TextField 微件的 InputDecoration() 下,添加 labelStyle:

TextField(
  controller: _usernameController,
  decoration: InputDecoration(
    labelText: 'Username',
    labelStyle: TextStyle(color: Theme.of(context).accentColor),
  ),
),
SizedBox(height: 12.0),
TextField(
  controller: _passwordController,
  decoration: InputDecoration(
    labelText: 'Password',
    labelStyle: TextStyle(color: Theme.of(context).accentColor),
  ),
),

为了让文本字段在聚焦和未聚焦时具有不同的标签样式,我们需要为每个 TextField 微件设置一个 FocusNode,并设置一个使 labelStyle 根据微件是否聚焦而动态变化的条件。

login.dart_LoginPageState 类顶部的文本字段控制器下,我们要初始化 FocusNodes 和未聚焦时的标签颜色:

class _LoginPageState extends State<LoginPage> {
  final _usernameController = TextEditingController();
  final _passwordController = TextEditingController();
  final _unfocusedColor = Colors.grey[600];
  final _usernameFocusNode = FocusNode();
  final _passwordFocusNode = FocusNode();

替换 initState 并为 FocusNodes 添加一个监听器:

@override
void initState() {
  super.initState();
  _usernameFocusNode.addListener(() {
      setState(() {
        //Redraw so that the username label reflects the focus state
      });
   });
  _passwordFocusNode.addListener(() {
      setState(() {
        //Redraw so that the password label reflects the focus state
      });
   });
}

最后,在 TextField 微件内添加 focusNode: 属性,并在 InputDecoration() 下为 labelStyle: 添加一个条件:

TextField(
  controller: _usernameController,
  decoration: InputDecoration(
    labelText: 'Username',
    labelStyle: TextStyle(
        color: _usernameFocusNode.hasFocus
           ? Theme.of(context).accentColor
           : _unfocusedColor),
  ),
  focusNode: _usernameFocusNode,
),
SizedBox(height: 12.0),
TextField(
  controller: _passwordController,
  decoration: InputDecoration(
    labelText: 'Password',
    labelStyle: TextStyle(
        color: _passwordFocusNode.hasFocus
           ? Theme.of(context).accentColor
           : _unfocusedColor),
  ),
  focusNode: _passwordFocusNode,
),

点击“Play”按钮。

Android

iOS

现在,您已经使用与 Shrine 匹配的特定颜色和字体排版为页面设置了样式,下面我们来看一看展示 Shrine 产品的卡片。目前,这些卡片位于网站导航旁的白色表面上。

调整卡片高度

home.dart 中,将 elevation: 值添加到卡片:

// TODO: Adjust card heights (103)

    elevation: 0.0,

保存项目。

Android

iOS

您已移除卡片下的阴影。

接下来,我们要在登录屏幕上更改组件的高度来衬托它。

更改“NEXT”按钮的高度

RaisedButton 的默认高度为 2。我们来增大这个值。

login.dart 中,将 elevation: 值添加到 NEXT RaisedButton:

RaisedButton(
  child: Text('NEXT'),
  elevation: 8.0, // New code

点击“Run”菜单下的“Flutter Hot Restart”按钮(以从头开始重启应用)。现在,登录屏幕应如下所示:

Android

iOS

Shrine 采用很酷的几何样式,通过八角形或矩形定义各种元素。接下来,我们要在主屏幕的卡片中以及登录屏幕的文本字段和按钮中实现这种形状样式设置。

更改登录屏幕上的文本字段形状

app.dart 中,导入一个特殊的切角边框文件:

import 'supplemental/cut_corners_border.dart';

还是在 app.dart 中,向文本字段装饰主题添加带有切角的形状:

// TODO: Decorate the inputs (103)
inputDecorationTheme: InputDecorationTheme(
  focusedBorder: CutCornersBorder(
    borderSide: BorderSide(
      width: 2.0,
      color: kShrineBrown900,
    ),
  ),
  border: CutCornersBorder(), // Replace code
),

更改登录屏幕上的按钮形状

login.dart 中,向 CANCEL 按钮添加斜角矩形边框:

FlatButton(
  child: Text('CANCEL'),
  shape: BeveledRectangleBorder(
    borderRadius: BorderRadius.all(Radius.circular(7.0)),
  ),

FlatButton 没有可见的形状,为什么要添加边框形状呢?因为在该按钮被触摸时,涟漪动画会绑定到同一个形状。

现在,向“NEXT”按钮添加相同的形状:

RaisedButton(
  child: Text('NEXT'),
  elevation: 8.0,
  shape: BeveledRectangleBorder(
    borderRadius: BorderRadius.all(Radius.circular(7.0)),
  ),

如需更改所有按钮的形状,我们还可以更新 app.dart 中的 buttonTheme。且把这个挑战留给学习者吧!

点击“Run”菜单下的“Flutter Hot Restart”按钮(以从头开始重启应用):

Android

iOS

接下来,我们要更改布局,以不同的宽高比和大小显示卡片,使每张卡片看起来都各不相同。

将 GridView 替换为 AsymmetricView

我们已经编写了一个非对称布局的文件。

home.dart 中,将整个文件更改为以下代码:

import 'package:flutter/material.dart';

import 'model/products_repository.dart';
import 'model/product.dart';
import 'supplemental/asymmetric_view.dart';

class HomePage extends StatelessWidget {
  // TODO: Add a variable for Category (104)

  @override
  Widget build(BuildContext context) {
  // TODO: Return an AsymmetricView (104)
  // TODO: Pass Category variable to AsymmetricView (104)
    return Scaffold(
      appBar: AppBar(
        brightness: Brightness.light,
        leading: IconButton(
          icon: Icon(Icons.menu),
          onPressed: () {
            print('Menu button');
          },
        ),
        title: Text('SHRINE'),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.search),
            onPressed: () {
              print('Search button');
            },
          ),
          IconButton(
            icon: Icon(Icons.tune),
            onPressed: () {
              print('Filter button');
            },
          ),
        ],
      ),
      body: AsymmetricView(products: ProductsRepository.loadProducts(Category.all)),
    );
  }
}

保存项目。

Android

iOS

现在,产品水平滚动,形成一种类似编织物的图案。此外,状态栏文本(顶部的时间和网络状态)现在为黑色。这是因为我们将 AppBar 的亮度更改为亮,即 brightness: Brightness.light

颜色是一种有力的品牌表达方式,而颜色的细微变化都会对用户体验产生巨大影响。为了检验这一点,我们来看看在品牌配色方案完全不同的情况下 Shrine 的外观如何。

修改颜色

colors.dart 中,添加以下代码:

const kShrinePurple = Color(0xFF5D1049);
const kShrineBlack = Color(0xFF000000);

app.dart 中,将 _buildShrineTheme()_buildShrineTextTheme 函数更改为以下代码:

ThemeData _buildShrineTheme() {
  final ThemeData base = ThemeData.light();
  return base.copyWith(
    primaryColor: kShrinePurple,
    buttonTheme: base.buttonTheme.copyWith(
      buttonColor: kShrinePurple,
      textTheme: ButtonTextTheme.primary,
      colorScheme: ColorScheme.light().copyWith(primary: kShrinePurple)
    ),
    scaffoldBackgroundColor: kShrineSurfaceWhite,
    textTheme: _buildShrineTextTheme(base.textTheme),
    primaryTextTheme: _buildShrineTextTheme(base.primaryTextTheme),
    accentTextTheme: _buildShrineTextTheme(base.accentTextTheme),
    primaryIconTheme: base.iconTheme.copyWith(
      color: kShrineSurfaceWhite
    ),
    inputDecorationTheme: InputDecorationTheme(
      focusedBorder: CutCornersBorder(
        borderSide: BorderSide(
          width: 2.0,
          color: kShrinePurple,
        ),
      ),
      border: CutCornersBorder(),
    ),
  );
}

TextTheme _buildShrineTextTheme(TextTheme base) {
  return base.copyWith(
    headline5: base.headline5.copyWith(
      fontWeight: FontWeight.w500,
    ),
    headline6: base.headline6.copyWith(
        fontSize: 18.0,
    ),
    caption: base.caption.copyWith(
      fontWeight: FontWeight.w400,
      fontSize: 14.0,
    ),
    bodyText1: base.bodyText1.copyWith(
      fontWeight: FontWeight.w500,
      fontSize: 16.0,
    ),
  ).apply(
    fontFamily: 'Rubik',
  );
}

login.dart 中,将钻石徽标设为黑色:

Image.asset(
  'assets/diamond.png',
  color: kShrineBlack, // New code
),

home.dart 中,将 AppBar 的亮度更改为暗:

brightness: Brightness.dark,

保存项目。此时应该会显示新的主题。

Android

iOS

Android

iOS

结果大不相同!在继续学习 104 之前,我们要还原此颜色代码。

下载 MDC-104 起始代码

现在,您已创建了一个与设计师提出的设计规范相似的应用。

后续步骤

现在,您已使用过以下 MDC 组件:主题、字体排版、高度和形状。您可以继续探索 MDC-Flutter 库中的更多组件和子系统。

请深入研究 supplemental 目录中的文件,了解如何创建水平滚动的非对称布局网格。

如果您规划的应用设计中包含的元素在 MDC 库中没有相应的组件,该怎么办?在 MDC-104:Material Design 高级组件中,我们将介绍如何使用 MDC 库创建自定义组件来实现特定外观。

下一个 Codelab

我能够用合理的时间和精力完成此 Codelab

非常赞同 赞同 中立 不赞同 非常不赞同

我希望日后继续使用 Material 组件

非常赞同 赞同 中立 不赞同 非常不赞同