什么是 Material Design 和 Flutter Material 组件

Material Design 意在为你构建一个大胆而且美观的数字产品设计系统。将风格、品牌、交互、动效通过统一的准则结合,发掘产品最大的设计潜力。

Flutter 的 Material 组件MDC - Flutter)通过在应用间和平台间提供一个统一的用户体验组件库,把设计和工程合二为一。秉承着 Google 的前端开发标准,Material Design 系统正在向多端一致体验、像素级完美呈现的方向发展。Material Design 组件(MDC)也同样适用于 Android、iOS 和 Web。

在本 Codelab 里,你将使用 MDC - Flutter 的几个组件构建一个登录页面。

最终效果预览

我们最终会构建一个售卖衣服和家居的电子商务应用 - Shrine,总共用四个 Codelab 来搞定它,本 Codelab 是其中的第一个,我们将带你一起使用 MDC - Flutter 来定制组件样式,以突显和匹配自身的品牌效果。

在本节,你将为 Shrine 应用构建一个登录页面,包含:

相关的 Codelabs 如下:

在 MDC Flutter 教程 4 结束时,你将有机会做出一个这样的应用:

此 Codelab 中的 MDC 组件

如何定位你的 Flutter 开发水平?

初学者 中级水平 专业

你需要安装两部分来完成本次实验,Flutter 的 SDK编辑器(editor),这个 codelab 里,我们以 Android Studio 作为编辑器(editor),但你可以用个人更顺手的编辑器。

你可以通过如下任何设备完成本 codelab:

下载起步应用

本项目位于 material-components-flutter-codelabs-101-starter/mdc_100_series 目录。

或者从 GitHub 克隆一份

使用以下命令从 GitHub 克隆此 Codelab 所需的起步应用:

git clone https://github.com/material-components/material-components-flutter-codelabs.git
cd material-components-flutter-Codelabs
git checkout 101-starter

设置你的工程

如下设置工程的方法是使用 Android Studio 做演示的。

创建新的工程

1. 在你的命令行工具里,切换到这个文件夹 material-components-flutter-codelabs

2. 执行命令 flutter create mdc_100_series

打开你的工程

1. 打开 Android Studio

2. 当你看到欢迎界面时候,选择打开一个已存在的工程(Open an existing Android Studio project.)

3. 打开这个文件夹 material-components-flutter-codelabs/mdc_100_series

如果此时提示一些错误请忽略,等第一次成功编译之后应该会好一些。

4. 在项目面板左侧,删除测试文件 ../test/widget_test.dart

5. 如果提示"升级平台和插件"或要配置 FlutterRunConfigurationType,请重启 Android Studio。

运行起步应用

下面我们以在 Android 模拟器或真机上为例做如下的步骤示范,当然如果你装有 Xcode,你也可以在 iOS 模拟器或真机上进行尝试。

1. 选择设备或模拟器

如果 Android 模拟器还没有运行起来,请选择 Tools -> Android -> AVD Manager 先进行 创建并启动模拟器 的操作。如果 AVD 里已经有创建好的模拟器,你可以直接在 IntelliJ 的设备选择列表里启动模拟器,如下一步所示。

(对于 iOS 模拟器,如果你还没有启动,请在你的电脑上选择 Flutter Device Selection -> Open iOS Simulator 来启动。)

2. 运行你的 Flutter 应用:

  • 在你的编辑器上方, Flutter 设备下拉菜单里,选择一款设备(比如选择 iPhone SE 或者某个 Android SDK 编译版本的设备)。
  • 点击 Play 按钮 ()。

成功了!包含 Shrine 登录页面的起步代码已经在你的模拟器里跑起来了。你可以看到 Shrine 的 logo ,下面是它的名字 "SHRINE"。

让我们来看一下代码。

login.dart 中的 Widgets

打开 login.dart ,它应该包含这样的内容:

import 'package:flutter/material.dart';

class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  // TODO: Add text editing controllers (101)
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: ListView(
          padding: EdgeInsets.symmetric(horizontal: 24.0),
          children: <Widget>[
            SizedBox(height: 80.0),
            Column(
              children: <Widget>[
                Image.asset('assets/diamond.png'),
                SizedBox(height: 16.0),
                Text('SHRINE'),
              ],
            ),
            SizedBox(height: 120.0),
            // TODO: Wrap Username with AccentColorOverride (103)
            // TODO: Remove filled: true values (103)
            // TODO: Wrap Password with AccentColorOverride (103)
            // TODO: Add TextField widgets (101)
            // TODO: Add button bar (101)
          ],
        ),
      ),
    );
  }
}

// TODO: Add AccentColorOverride (103)

它包含一条 import 声明和两个新的类:

首先我们将为登录页面添加两个文本框,用于用户输入用户名和密码。我们会用到 TextField widget,它有一个悬浮的标签,并有触摸波纹效果。

这个页面主要由一个 ListView 组成,它将其子项排列在一个可滚动的列中。让我们把文本框放到底部。

添加 TextField widgets

添加两个新文本框,并通过 SizedBox(height: 120.0) 添加一个空位符。

// TODO: Add TextField widgets (101)
// [Name]
TextField(
  decoration: InputDecoration(
    filled: true,
    labelText: 'Username',
  ),
),
// spacer
SizedBox(height: 12.0),
// [Password]
TextField(
  decoration: InputDecoration(
    filled: true,
    labelText: 'Password',
  ),
  obscureText: true,
),

两个文本框都包含一个 decoration 字段,值是一个 InputDecoration widget 。其中 filled 指该文本框的背景将被一个浅色填充,以助于用户分辨出点击或触摸区域。第二个文本框中 obscureText: true 是指将用户的输入自动替换为星号,一般用于密码文本框。

保存项目,会自动触发热重载功能。

现在你应该看到 Username 和 Password 两个文本框了!查看一下它们的悬浮标签和 ink 波纹效果:

If the app doesn't update, click the "Play" button again, or click "Stop" followed by "Play."

接下来,我们将为登录页面添加两个按钮:"Cancel" 和 "Next" 。我们将使用两种 MDC 按钮 widget :FlatButton (在 Material Guidelines 中称为 "Text Button" )和 RaisedButton (也称 "Contained Button" )。

添加 ButtonBar

在文本框之后 ,向 ListView 的子项中添加 ButtonBar

// TODO: Add button bar (101)
ButtonBar(
  // TODO: Add a beveled rectangular border to CANCEL (103)
  children: <Widget>[
    // TODO: Add buttons (101)
  ],
),

ButtonBar 把子项排列为一行。

添加按钮

然后,向 ButtonBar 的子项列表添加两个按钮:

    // TODO: Add buttons (101)
    FlatButton(
      child: Text('CANCEL'),
      onPressed: () {
        // TODO: Clear the text fields (101)
      },
    ),
    // TODO: Add an elevation to NEXT (103)
    // TODO: Add a beveled rectangular border to NEXT (103)
    RaisedButton(
      child: Text('NEXT'),
      onPressed: () {
    // TODO: Show the next page (101) 
      },
    ),

保存项目。在后一个文本框的下面,你应该看到出现了两个按钮。

ButtonBar 来为你处理布局。它将按钮水平放置,按钮们会按照当前的 ButtonTheme (你将在 Codelab MDC-103 中了解更多关于它的知识)依次排列。

触碰按钮会触发一次 ink 波纹效果,但目前仅限于此。让我们来给匿名的 onPressed 方法加上功能代码,让 Cancel 按钮来清除文本框,让 Next 按钮可以退出界面:

添加 TextEditingControllers

为了实现清除文本框内容,我们需要添加 TextEditingControllers 来控制文本。

_LoginPageState 类的开头 ,创建 controller 变量,并声明为 final 类型 。

  // TODO: Add text editing controllers (101)
  final _usernameController = TextEditingController();
  final _passwordController = TextEditingController();

在第一个 TextField 中增加 controller: _usernameController

// [Name]
TextField(
  controller: _usernameController,

在第二个 TextField 中增加 controller: _passwordController

// [Password]
TextField(
  controller: _passwordController,

编辑 onPressed

在 FlatButton 的 onPressed 方法中添加代码,让两个 controller 清空各自的文本内容:

    // TODO: Clear the text fields (101)
    _usernameController.clear();
    _passwordController.clear();

保存项目。现在当你在文本框中输入了内容后,点击 Cancel 就会把内容都清空掉了。

这个登录表单看起来还不错!接下来我们来让用户可以进入到 Shrine 的其他页面吧。

出栈

要退出当前页面,我们要把这一页( Flutter 称为一个 route )从 navigation 栈中出栈(或者移除)。

在 RaisedButton 的 onPressed 方法中,将 Navigator 里最新加入的 route 出栈:

    // TODO: Show the next page (101) 
                RaisedButton(
                  child: Text('NEXT'),
                  onPressed: () {
                    Navigator.pop(context);
                  },
                ),

保存项目。点击 "Next" 试一下。

是的,你完成了!

这一界面是我们下一个 Codelab 的起始点,你会在 MDC-102 中遇到它。

我们添加了文本框和按钮,并且几乎不用考虑布局。Flutter Material 组件带有许多样式,而且布局几乎毫不费力。

下一步

文本框和按钮是 Material 体系的两个核心组件,除此之外还有很多其他的组件!可以访问 widgets in Flutter's Material Components library 进一步探索。

或者你也可以前往 MDC-102: Material Design Structure and Layout 来学习 Flutter MDC-102 中所涉及的组件。

我能够用合理的时间和精力完成这个代码库

非常赞同 赞同 一般 不赞同 非常不赞同

我希望将来继续使用 Material Components

非常赞同 赞同 一般 不赞同 非常不赞同