概述

#

Flutter 布局机制的核心是 widget。在 Flutter 中,几乎所有东西都是 widget——甚至布局模型也是 widget。你在 Flutter 应用中看到的图像、图标和文本都是 widget。但你没有看到的东西也是 widget,例如用于排列、约束和对齐可见 widget 的行、列和网格。你通过组合 widget 来构建更复杂的 widget,从而创建布局。

概念示例

#

在以下示例中,第一张截图显示了带有标签的三个图标,第二张截图包含了行和列的视觉布局。在第二张截图中,debugPaintSizeEnabled 设置为 true,这样你就可以看到视觉布局。

Sample layout
Sample layout with visual debugging

这是上一个示例的 widget 树图

Node tree

大部分内容应该和你预期的一样,但你可能想知道容器(显示为粉红色)是什么。Container 是一个 widget 类,允许你自定义其子 widget。当你想要添加内边距、外边距、边框或背景颜色等功能时,可以使用 Container

每个 Text widget 都放置在一个 Container 中以添加外边距。整个 Row 也放置在一个 Container 中以在行周围添加内边距。

UI 的其余部分由属性控制。使用 color 属性设置 Icon 的颜色。使用 Text.style 属性设置字体、颜色、字重等。列和行都有属性,允许你指定其子项如何垂直或水平对齐,以及子项应占据多少空间。

布局 widget

#

如何在 Flutter 中布局单个 widget?本节向你展示如何创建和显示一个简单的 widget。它还显示了一个简单的 Hello World 应用程序的完整代码。

在 Flutter 中,在屏幕上放置文本、图标或图像只需要几个步骤。

1. 选择布局 widget

#

根据你希望如何对齐或约束可见 widget 来选择各种布局 widget,因为这些特性通常会传递给包含的 widget。

例如,你可以使用 Center 布局 widget 将可见 widget 水平和垂直居中。

dart
Center(
  // Content to be centered here.
)

2. 创建可见 widget

#

为你的应用选择一个可见 widget,以包含可见元素,例如文本图像图标

例如,你可以使用 Text widget 来显示一些文本

dart
Text('Hello World')

3. 将可见 widget 添加到布局 widget 中

#

所有布局 widget 都有以下其中之一:

  • 如果它们只接受一个子项,则为 child 属性——例如 CenterContainer
  • 如果它们接受一个 widget 列表,则为 children 属性——例如 RowColumnListViewStack

Text widget 添加到 Center widget 中

dart
const Center(
  child: Text('Hello World'),
),

4. 将布局 widget 添加到页面中

#

Flutter 应用程序本身就是一个 widget,大多数 widget 都有一个 build() 方法。在应用程序的 build() 方法中实例化并返回一个 widget 将显示该 widget。

对于一个通用应用,你可以将 Container widget 添加到应用的 build() 方法中

dart
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: const BoxDecoration(color: Colors.white),
      child: const Center(
        child: Text(
          'Hello World',
          textDirection: TextDirection.ltr,
          style: TextStyle(fontSize: 32, color: Colors.black87),
        ),
      ),
    );
  }
}

默认情况下,通用应用不包含 AppBar、标题或背景颜色。如果你想在通用应用中拥有这些功能,你必须自己构建它们。这个应用将背景颜色改为白色,文本改为深灰色,以模仿 Material 应用。

对于 Material 应用,你可以使用 Scaffold widget;它提供默认的横幅、背景颜色,并提供用于添加抽屉、SnackBar 和底部工作表的 API。然后你可以将 Center widget 直接添加到主页的 body 属性中。

dart
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    const String appTitle = 'Flutter layout demo';
    return MaterialApp(
      title: appTitle,
      home: Scaffold(
        appBar: AppBar(title: const Text(appTitle)),
        body: const Center(
          child: Text('Hello World'),
        ),
      ),
    );
  }
}

要创建 Cupertino 应用,请使用 CupertinoAppCupertinoPageScaffold widget。

Material 不同,它不提供默认横幅或背景颜色。你需要自己设置这些。

  • 要设置默认颜色,请将配置好的 CupertinoThemeData 传递给应用的 theme 属性。

  • 要在应用的顶部添加 iOS 风格的导航栏,请将 CupertinoNavigationBar widget 添加到脚手架的 navigationBar 属性中。你可以使用 CupertinoColors 提供的颜色来配置你的 widget,使其与 iOS 设计相匹配。

  • 要布局你的应用程序主体,请将脚手架的 child 属性设置为所需的 widget,例如 CenterColumn

要了解可以添加哪些其他 UI 组件,请查看 Cupertino 库

dart
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter layout demo',
      theme: CupertinoThemeData(
        brightness: Brightness.light,
        primaryColor: CupertinoColors.systemBlue,
      ),
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          backgroundColor: CupertinoColors.systemGrey,
          middle: Text('Flutter layout demo'),
        ),
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [Text('Hello World')],
          ),
        ),
      ),
    );
  }
}

5. 运行你的应用

#

添加 widget 后,运行你的应用。当你运行应用时,应该会看到 Hello World

应用源代码

Screenshot of app displaying Hello World

垂直和水平布局多个 widget

#

最常见的布局模式之一是垂直或水平排列 widget。你可以使用 Row widget 水平排列 widget,使用 Column widget 垂直排列 widget。

要在 Flutter 中创建行或列,你需要将子 widget 列表添加到 RowColumn widget 中。反过来,每个子项本身可以是行或列,依此类推。以下示例显示了如何在行或列内部嵌套行或列。

此布局组织为 Row。该行包含两个子项:左侧是一个列,右侧是一个图像。

Screenshot with callouts showing the row containing two children

左侧列的 widget 树嵌套了行和列。

Diagram showing a left column broken down to its sub-rows and sub-columns

你将在嵌套行和列中实现 Pavlova 的部分布局代码。

对齐 widget

#

你可以使用 mainAxisAlignmentcrossAxisAlignment 属性控制行或列如何对齐其子项。对于行,主轴水平运行,交叉轴垂直运行。对于列,主轴垂直运行,交叉轴水平运行。

Diagram showing the main axis and cross axis for a row
Diagram showing the main axis and cross axis for a column

MainAxisAlignmentCrossAxisAlignment 枚举提供了各种常量来控制对齐方式。

在以下示例中,3 张图像中的每张都宽 100 像素。渲染框(在本例中为整个屏幕)宽于 300 像素,因此将主轴对齐方式设置为 spaceEvenly 会在每张图像之间、之前和之后均匀分配水平自由空间。

dart
Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [
    Image.asset('images/pic1.jpg'),
    Image.asset('images/pic2.jpg'),
    Image.asset('images/pic3.jpg'),
  ],
);
Row with 3 evenly spaced images

应用源代码: row_column

列的工作方式与行相同。以下示例显示了一列 3 张图像,每张高 100 像素。渲染框的高度(在本例中为整个屏幕)大于 300 像素,因此将主轴对齐方式设置为 spaceEvenly 会在每张图像之间、上方和下方均匀分配垂直自由空间。

dart
Column(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [
    Image.asset('images/pic1.jpg'),
    Image.asset('images/pic2.jpg'),
    Image.asset('images/pic3.jpg'),
  ],
);
Column showing 3 images spaced evenly

应用源代码: row_column

设置 widget 大小

#

当布局太大无法适应设备时,受影响的边缘会出现黄黑相间的条纹图案。这是一个行太宽的示例

Overly-wide row

可以使用 Expanded widget 来调整 widget 的大小,使其适应行或列。要修复上一个示例中图像行太宽而无法适应其渲染框的问题,请将每个图像用 Expanded widget 包装起来。

dart
Row(
  crossAxisAlignment: CrossAxisAlignment.center,
  children: [
    Expanded(child: Image.asset('images/pic1.jpg')),
    Expanded(child: Image.asset('images/pic2.jpg')),
    Expanded(child: Image.asset('images/pic3.jpg')),
  ],
);
Row of 3 images that are too wide, but each is constrained to take only 1/3 of the space

应用源代码: sizing

也许你希望一个 widget 占据其同级两倍的空间。为此,请使用 Expanded widget 的 flex 属性,这是一个整数,用于确定 widget 的 flex 因子。默认的 flex 因子为 1。以下代码将中间图像的 flex 因子设置为 2

dart
Row(
  crossAxisAlignment: CrossAxisAlignment.center,
  children: [
    Expanded(child: Image.asset('images/pic1.jpg')),
    Expanded(flex: 2, child: Image.asset('images/pic2.jpg')),
    Expanded(child: Image.asset('images/pic3.jpg')),
  ],
);
Row of 3 images with the middle image twice as wide as the others

应用源代码: sizing

紧凑排列 widget

#

默认情况下,行或列会尽可能占据其主轴上的空间,但如果你想将子项紧密地排列在一起,请将其 mainAxisSize 设置为 MainAxisSize.min。以下示例使用此属性将星形图标紧密地排列在一起。

dart
Row(
  mainAxisSize: MainAxisSize.min,
  children: [
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    const Icon(Icons.star, color: Colors.black),
    const Icon(Icons.star, color: Colors.black),
  ],
)
Row of 5 stars, packed together in the middle of the row

应用源代码: pavlova

嵌套行和列

#

布局框架允许你根据需要将行和列嵌套在行和列中。让我们看看以下布局中带轮廓部分的的代码

Screenshot of the pavlova app, with the ratings and icon rows outlined in red

带轮廓的部分实现为两行。评分行包含五颗星和评论数量。图标行包含三列图标和文本。

评分行的 widget 树

Ratings row widget tree

ratings 变量创建了一个行,其中包含一个较小的 5 星图标行和文本

dart
final stars = Row(
  mainAxisSize: MainAxisSize.min,
  children: [
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    const Icon(Icons.star, color: Colors.black),
    const Icon(Icons.star, color: Colors.black),
  ],
);

final ratings = Container(
  padding: const EdgeInsets.all(20),
  child: Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: [
      stars,
      const Text(
        '170 Reviews',
        style: TextStyle(
          color: Colors.black,
          fontWeight: FontWeight.w800,
          fontFamily: 'Roboto',
          letterSpacing: 0.5,
          fontSize: 20,
        ),
      ),
    ],
  ),
);

图标行位于评分行下方,包含 3 列;每列包含一个图标和两行文本,你可以在其 widget 树中看到

Icon widget tree

iconList 变量定义了图标行

dart
const descTextStyle = TextStyle(
  color: Colors.black,
  fontWeight: FontWeight.w800,
  fontFamily: 'Roboto',
  letterSpacing: 0.5,
  fontSize: 18,
  height: 2,
);

// DefaultTextStyle.merge() allows you to create a default text
// style that is inherited by its child and all subsequent children.
final iconList = DefaultTextStyle.merge(
  style: descTextStyle,
  child: Container(
    padding: const EdgeInsets.all(20),
    child: Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        Column(
          children: [
            Icon(Icons.kitchen, color: Colors.green[500]),
            const Text('PREP:'),
            const Text('25 min'),
          ],
        ),
        Column(
          children: [
            Icon(Icons.timer, color: Colors.green[500]),
            const Text('COOK:'),
            const Text('1 hr'),
          ],
        ),
        Column(
          children: [
            Icon(Icons.restaurant, color: Colors.green[500]),
            const Text('FEEDS:'),
            const Text('4-6'),
          ],
        ),
      ],
    ),
  ),
);

leftColumn 变量包含评分和图标行,以及描述 Pavlova 的标题和文本

dart
final leftColumn = Container(
  padding: const EdgeInsets.fromLTRB(20, 30, 20, 20),
  child: Column(children: [titleText, subTitle, ratings, iconList]),
);

左侧列放置在 SizedBox 中以约束其宽度。最后,UI 是通过将整个行(包含左侧列和图像)放置在 Card 中来构建的。

Pavlova 图像来自 Pixabay。你可以使用 Image.network() 嵌入来自网络的图像,但在此示例中,图像保存到项目中的 images 目录,添加到 pubspec 文件中,并使用 Images.asset() 访问。有关更多信息,请参阅添加资源和图像

dart
body: Center(
  child: Container(
    margin: const EdgeInsets.fromLTRB(0, 40, 0, 30),
    height: 600,
    child: Card(
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          SizedBox(width: 440, child: leftColumn),
          mainImage,
        ],
      ),
    ),
  ),
),

应用源代码: pavlova


常用布局 widget

#

Flutter 拥有丰富的布局 widget 库。以下是其中最常用的一些。目的是让你尽快上手,而不是用完整的列表让你不知所措。有关其他可用 widget 的信息,请参阅Widget 目录,或使用API 参考文档中的搜索框。此外,API 文档中的 widget 页面通常会提供有关可能更适合你需求的类似 widget 的建议。

以下 widget 分为两类:widget 库中的标准 widget,以及 Material 库中的专用 widget。任何应用都可以使用 widget 库,但只有 Material 应用才能使用 Material Components 库。

容器
为 widget 添加内边距、外边距、边框、背景颜色或其他装饰。
GridView
将 widget 布局为可滚动的网格。
ListView
将 widget 布局为可滚动的列表。
层叠布局
将一个 widget 叠放在另一个 widget 之上。
Scaffold
提供一个结构化的布局框架,带有用于常见 Material Design 应用程序元素的插槽。
AppBar
创建一个通常显示在屏幕顶部的水平条。
Card
将相关信息组织到一个带有圆角和阴影的框中。
ListTile
将最多 3 行文本以及可选的前导和尾随图标组织成一行。
CupertinoPageScaffold
为 iOS 风格的页面提供基本布局结构。
CupertinoNavigationBar
在屏幕顶部创建 iOS 风格的导航栏。
CupertinoSegmentedControl
创建用于选择的分段控件。
CupertinoTabBarCupertinoTabScaffold
创建 iOS 特有的底部标签栏。

容器

#

许多布局大量使用 Container 来使用内边距分隔 widget,或添加边框或外边距。你可以通过将整个布局放入 Container 中并更改其背景颜色或图像来更改设备的背景。

Container 摘要

#
  • 添加内边距、外边距、边框
  • 更改背景颜色或图像
  • 包含单个子 widget,但该子 widget 可以是 RowColumn,甚至是 widget 树的根
Diagram showing: margin, border, padding, and content

Container 示例

#

此布局由两行组成,每行包含 2 张图像。使用 Container 将列的背景颜色更改为较浅的灰色。

dart
Widget _buildImageColumn() {
  return Container(
    decoration: const BoxDecoration(color: Colors.black26),
    child: Column(children: [_buildImageRow(1), _buildImageRow(3)]),
  );
}
Screenshot showing 2 rows, each containing 2 images

Container 还用于为每个图像添加圆角边框和外边距

dart
Widget _buildDecoratedImage(int imageIndex) => Expanded(
  child: Container(
    decoration: BoxDecoration(
      border: Border.all(width: 10, color: Colors.black38),
      borderRadius: const BorderRadius.all(Radius.circular(8)),
    ),
    margin: const EdgeInsets.all(4),
    child: Image.asset('images/pic$imageIndex.jpg'),
  ),
);

Widget _buildImageRow(int imageIndex) => Row(
  children: [
    _buildDecoratedImage(imageIndex),
    _buildDecoratedImage(imageIndex + 1),
  ],
);

你可以在教程中找到更多 Container 示例。

应用源代码: container


GridView

#

使用 GridView 将 widget 布局为二维列表。GridView 提供了两个预制的列表,你也可以构建自己的自定义网格。当 GridView 检测到其内容太长而无法适应渲染框时,它会自动滚动。

GridView 摘要

#
  • 在网格中布局 widget
  • 检测到列内容超出渲染框时自动提供滚动
  • 构建你自己的自定义网格,或使用提供的网格之一
    • GridView.count 允许你指定列数
    • GridView.extent 允许你指定瓷砖的最大像素宽度

GridView 示例

#
A 3-column grid of photos

使用 GridView.extent 创建一个最大宽度为 150 像素的网格。

应用源代码: grid_and_list

A 2 column grid with footers

使用 GridView.count 创建一个网格,在纵向模式下宽 2 个瓷砖,在横向模式下宽 3 个瓷砖。通过设置每个 GridTilefooter 属性来创建标题。

Dart 代码: grid_list_demo.dart

dart
Widget _buildGrid() => GridView.extent(
  maxCrossAxisExtent: 150,
  padding: const EdgeInsets.all(4),
  mainAxisSpacing: 4,
  crossAxisSpacing: 4,
  children: _buildGridTileList(30),
);

// The images are saved with names pic0.jpg, pic1.jpg...pic29.jpg.
// The List.generate() constructor allows an easy way to create
// a list when objects have a predictable naming pattern.
List<Widget> _buildGridTileList(int count) =>
    List.generate(count, (i) => Image.asset('images/pic$i.jpg'));

ListView

#

ListView 是一种类似列的 widget,当其内容太长而无法适应其渲染框时,它会自动提供滚动。

ListView 摘要

#
  • 一种专门的 Column,用于组织箱体列表
  • 可以水平或垂直布局
  • 检测到内容不适合时提供滚动
  • Column 配置性低,但更易于使用并支持滚动

ListView 示例

#
ListView containing movie theaters and restaurants

使用 ListView 显示一个使用 ListTile 的企业列表。一个 Divider 将电影院与餐馆分开。

应用源代码: grid_and_list

ListView containing shades of blue

使用 ListView 显示特定颜色系列的 Colors,取自 Material 2 设计调色板

Dart 代码: colors_demo.dart

dart
Widget _buildList() {
  return ListView(
    children: [
      _tile('CineArts at the Empire', '85 W Portal Ave', Icons.theaters),
      _tile('The Castro Theater', '429 Castro St', Icons.theaters),
      _tile('Alamo Drafthouse Cinema', '2550 Mission St', Icons.theaters),
      _tile('Roxie Theater', '3117 16th St', Icons.theaters),
      _tile(
        'United Artists Stonestown Twin',
        '501 Buckingham Way',
        Icons.theaters,
      ),
      _tile('AMC Metreon 16', '135 4th St #3000', Icons.theaters),
      const Divider(),
      _tile('K\'s Kitchen', '757 Monterey Blvd', Icons.restaurant),
      _tile('Emmy\'s Restaurant', '1923 Ocean Ave', Icons.restaurant),
      _tile('Chaiya Thai Restaurant', '272 Claremont Blvd', Icons.restaurant),
      _tile('La Ciccia', '291 30th St', Icons.restaurant),
    ],
  );
}

ListTile _tile(String title, String subtitle, IconData icon) {
  return ListTile(
    title: Text(
      title,
      style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 20),
    ),
    subtitle: Text(subtitle),
    leading: Icon(icon, color: Colors.blue[500]),
  );
}

层叠布局

#

使用 Stack 将 widget 排列在基础 widget(通常是图像)之上。widget 可以完全或部分覆盖基础 widget。

Stack 摘要

#
  • 用于重叠其他 widget 的 widget
  • 子列表中的第一个 widget 是基础 widget;随后的子项会覆盖在该基础 widget 上
  • Stack 的内容无法滚动
  • 你可以选择裁剪超出渲染框的子项

Stack 示例

#
Circular avatar image with a label

使用 StackCircleAvatar 之上叠加一个 Container(它在半透明黑色背景上显示其 Text)。Stack 使用 alignment 属性和 Alignments 偏移文本。

应用源代码: card_and_stack

An image with a icon overlaid on top

使用 Stack 在图像之上叠加图标。

Dart 代码: bottom_navigation_demo.dart

dart
Widget _buildStack() {
  return Stack(
    alignment: const Alignment(0.6, 0.6),
    children: [
      const CircleAvatar(
        backgroundImage: AssetImage('images/pic.jpg'),
        radius: 100,
      ),
      Container(
        decoration: const BoxDecoration(color: Colors.black45),
        child: const Text(
          'Mia B',
          style: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.bold,
            color: Colors.white,
          ),
        ),
      ),
    ],
  );
}

Card

#

Card,来自 Material 库,包含相关信息片段,可以由几乎任何 widget 组成,但通常与 ListTile 一起使用。Card 只有一个子项,但其子项可以是列、行、列表、网格或其他支持多个子项的 widget。默认情况下,Card 将其大小缩小到 0 乘 0 像素。你可以使用 SizedBox 来约束卡片的大小。

在 Flutter 中,Card 具有略微圆角和阴影,使其具有 3D 效果。更改 Cardelevation 属性可以控制阴影效果。例如,将高程设置为 24 会使 Card 在视觉上从表面进一步抬起,并使阴影更加分散。有关支持的高程值列表,请参阅 Material 指南中的高程。指定不支持的值会完全禁用阴影。

Card 摘要

#
  • 实现 Material 卡片
  • 用于呈现相关信息片段
  • 接受单个子项,但该子项可以是 RowColumn 或其他包含子项列表的 widget
  • 显示时带有圆角和阴影
  • Card 的内容无法滚动
  • 来自 Material 库

Card 示例

#
Card containing 3 ListTiles

一个包含 3 个 ListTile 的 Card,并通过使用 SizedBox 包装来设置大小。一个 Divider 分隔第一个和第二个 ListTile

应用源代码: card_and_stack

Tappable card containing an image and multiple forms of text

一个包含图像和文本的 Card

Dart 代码: cards_demo.dart

dart
Widget _buildCard() {
  return SizedBox(
    height: 210,
    child: Card(
      child: Column(
        children: [
          ListTile(
            title: const Text(
              '1625 Main Street',
              style: TextStyle(fontWeight: FontWeight.w500),
            ),
            subtitle: const Text('My City, CA 99984'),
            leading: Icon(Icons.restaurant_menu, color: Colors.blue[500]),
          ),
          const Divider(),
          ListTile(
            title: const Text(
              '(408) 555-1212',
              style: TextStyle(fontWeight: FontWeight.w500),
            ),
            leading: Icon(Icons.contact_phone, color: Colors.blue[500]),
          ),
          ListTile(
            title: const Text('costa@example.com'),
            leading: Icon(Icons.contact_mail, color: Colors.blue[500]),
          ),
        ],
      ),
    ),
  );
}

ListTile

#

使用 ListTile,这是一个来自 Material 库的专用行 widget,可以轻松创建一个包含最多 3 行文本以及可选的前导和尾随图标的行。ListTile 最常用于 CardListView,但也可以用于其他地方。

ListTile 摘要

#
  • 一种专用行,包含最多 3 行文本和可选图标
  • Row 配置性低,但更易于使用
  • 来自 Material 库

ListTile 示例

#
Card containing 3 ListTiles

一个包含 3 个 ListTileCard

应用源代码: card_and_stack

4 ListTiles, each containing a leading avatar

使用带有前导 widget 的 ListTile

Dart 代码: list_demo.dart


约束

#

要完全理解 Flutter 的布局系统,你需要了解 Flutter 如何定位和调整布局中组件的大小。有关更多信息,请参阅理解约束

视频

#

以下视频是 Flutter in Focus 系列的一部分,解释了 StatelessStateful widget。

在新标签页中在 YouTube 上观看:“如何创建无状态 widget”

在新标签页中在 YouTube 上观看:“有状态 widget 如何以及何时最适合使用”

Flutter in Focus 播放列表


Widget of the Week 系列的每一集都专注于一个 widget。其中一些包括布局 widget。

在新标签页中在 YouTube 上观看:“Widget of the Week 介绍”

Flutter Widget of the Week 播放列表

其他资源

#

以下资源可能有助于编写布局代码。

布局教程
学习如何构建布局。
组件目录
描述了 Flutter 中许多可用的 widget。
Flutter 中的 HTML/CSS 类比
对于熟悉 Web 编程的人,此页面将 HTML/CSS 功能映射到 Flutter 功能。
API 参考文档
所有 Flutter 库的参考文档。
添加资源和图像
解释如何将图像和其他资源添加到你的应用程序包中。
从零到一使用 Flutter
一个人编写第一个 Flutter 应用程序的经验。