# 给 React Native 开发者的 Flutter 指南

> 学习如何把 React Native 的开发经验应用到 Flutter 应用的开发中。



<?code-excerpt path-base="get-started/flutter-for/react_native_devs"?>

This document is for React Native (RN) developers looking to apply their
existing RN knowledge to build mobile apps with Flutter. If you understand
the fundamentals of the RN framework then you can use this document as a
way to get started learning Flutter development.

本文面向希望基于现有的 React Native（下文统称 RN）的知识结构使用
Flutter 开发移动端应用的开发者。
如果你已经对 RN 的框架有所了解，
那么你可以通过这个文档入门 Flutter 开发。

This document can be used as a cookbook by jumping around and finding
questions that are most relevant to your needs.

本文可以当做查询手册使用，里面涉及到的问题基本上可以满足需求。

## Introduction to Dart for JavaScript Developers (ES6)

## 针对 JavaScript (ES6) 开发者的 Dart 介绍

Like React Native, Flutter uses reactive-style views. However, while RN
transpiles to native widgets, Flutter compiles all the way to native code.
Flutter controls each pixel on the screen, which avoids performance problems
caused by the need for a JavaScript bridge.

与 RN 一样，Flutter 使用响应式风格的界面编写方式。
然而，RN 需要被转译为本地对应的 widget，
而 Flutter 是直接编译成原生代码运行。
Flutter 可以控制屏幕上的每一个像素，
由此可以避免使用 JavaScript Bridge 导致的性能问题。

Dart is an easy language to learn and offers the following features:

Dart 学习起来非常简单，包含如下特性：

* Provides an open-source, scalable programming language for building web,
  server, and mobile apps.

  它针对 web 服务和移动应用开发提供了一种开源的，可扩展的编程语言。

* Provides an object-oriented, single inheritance language that uses a C-style
  syntax that is AOT-compiled into native.

  它提供了一种面向对象的单继承语言，使用 C 语言风格的语法并且可通过 AOT 编译为本地代码。

* Transcompiles optionally into JavaScript.

  可转译为 JavaScript 代码。

* Supports interfaces and abstract classes.

  支持接口和抽象类。

A few examples of the differences between JavaScript and Dart are described
below.

下面的几个例子解释了 JavaScript 和 Dart 的区别。

### Entry point

### 入口函数

JavaScript doesn't have a pre-defined entry
function&mdash;you define the entry point.

JavaScript 并没有预定义的入口函数。

```js
// JavaScript
function startHere() {
  // Can be used as entry point
}
```

In Dart, every app must have a top-level `main()` function that serves as the
entry point to the app.

在 Dart 里，每个应用程序必须有一个最顶级的 `main()` 函数，该函数作为应用程序的入口函数。

<?code-excerpt "lib/main.dart (main)"?>
```dart
/// Dart
void main() {}
```

Try it out in [DartPad][DartPadA].

可以在这里查看效果 [DartPad][DartPadA]。

### Printing to the console

### 在控制台打印输出

To print to the console in Dart, use `print()`.

在 Dart 中如果需要在控制台进行输出，调用 `print()`。

```js
// JavaScript
console.log('Hello world!');
```

<?code-excerpt "lib/main.dart (print)"?>
```dart
/// Dart
print('Hello world!');
```

Try it out in [DartPad][DartPadB].

可以在这里查看效果 [DartPad][DartPadB]。

### Variables

### 变量

Dart is type safe&mdash;it uses a combination of static type checking
and runtime checks to ensure that a variable's value always matches
the variable's static type. Although types are mandatory,
some type annotations are optional because
Dart performs type inference.

Dart 是类型安全的，它会结合静态类型检查和运行时检查，
来保证变量的值总是和变量的静态类型相匹配。
虽然类型是语法要求，有些类型标注也并不是必须要填的，
因为 Dart 使用类型推断。

#### Creating and assigning variables

#### 创建变量并赋值

In JavaScript, variables cannot be typed.

在 JavaScript 中，变量是无法指定类型的。

In [Dart][], variables must either be explicitly
typed or the type system must infer the proper type automatically.

在 [Dart][] 中，变量可以显式定义类型，或者类型系统自动判断变量的类型。

```js
// JavaScript
let name = 'JavaScript';
```

<?code-excerpt "lib/main.dart (variables)"?>
```dart
/// Dart
/// Both variables are acceptable.
String name = 'dart'; // Explicitly typed as a [String].
var otherName = 'Dart'; // Inferred [String] type.
```

Try it out in [DartPad][DartPadC].

可以在这里查看效果 [DartPad][DartPadC]。

For more information, see [Dart's Type System][].

如果想了解更多相关信息，请参考 [Dart 的类型系统][Dart's Type System]。

#### Default value

#### 默认值

In JavaScript, uninitialized variables are `undefined`.

在 JavaScript 中，未初始化的变量是 `undefined`。

In Dart, uninitialized variables have an initial value of `null`.
Because numbers are objects in Dart, even uninitialized variables with
numeric types have the value `null`.

在 Dart 中，未初始化的变量会有一个初始值 `null`。
因为数字在 Dart 是对象，甚至未初始化的数字类型的变量也会是 `null`。

:::note

As of 2.12, Dart supports [Sound Null Safety][],
all underlying types are non-nullable by default,
which must be initialized as a non-nullable value.

自 Dart 2.12 起，[健全的空安全][Sound Null Safety] 已完全支持，
所有的基础类型默认都为非空，在使用时必须要初始化为非空的值。

:::

```js
// JavaScript
let name; // == undefined
```

<?code-excerpt "lib/main.dart (null)"?>
```dart
// Dart
var name; // == null; raises a linter warning
int? x; // == null
```

Try it out in [DartPad][DartPadD].

可以在这里查看效果 [DartPad][DartPadD]。

For more information, see the documentation on
[variables][].

如果想了解更多详细内容，请查看这个文档 [variables][]。

### Checking for null or zero

### 检查 null 或者零值

In JavaScript, values of 1 or any non-null objects
are treated as `true` when using the `==` comparison operator.

在 JavaScript 中，1 或者任何非空对象在使用
`==` 比较操作符时都会被隐式转换为 `true`。

```js
// JavaScript
let myNull = null;
if (!myNull) {
  console.log('null is treated as false');
}
let zero = 0;
if (!zero) {
  console.log('0 is treated as false');
}
```

In Dart, only the boolean value `true` is treated as true.

在 Dart 中，只有布尔类型值 `true` 才是 true。

<?code-excerpt "lib/main.dart (true)"?>
```dart
/// Dart
var myNull = potentiallyNull();
if (myNull == null) {
  print('use "== null" to check null');
}
var zero = 0;
if (zero == 0) {
  print('use "== 0" to check zero');
}
```

Try it out in [DartPad][DartPadE].

可以在这里查看效果 [DartPad][DartPadE]。

### Functions

### 函数

Dart and JavaScript functions are generally similar.
The primary difference is the declaration.

Dart 和 JavaScript 中的函数很相似。最大的区别是声明格式。

```js
// JavaScript
function fn() {
  return true;
}
```

<?code-excerpt "lib/main.dart (function)"?>
```dart
/// Dart
/// You can explicitly define the return type.
bool fn() {
  return true;
}
```

Try it out in [DartPad][DartPadF].

可以在这里查看效果 [DartPad][DartPadF]。

For more information, see the documentation on
[functions][].

如果想了解更多相关信息，可以参考 [函数][functions] 介绍。

### Asynchronous programming

### 异步编程

#### Futures

Like JavaScript, Dart supports single-threaded execution. In JavaScript,
the Promise object represents the eventual completion (or failure)
of an asynchronous operation and its resulting value.

Dart 与 JavaScript 类似，同样是单线程模型。
在 JavaScript 中，Promise 对象代表异步操作的完成或者失败。

Dart uses [`Future`][] objects to handle this.

Dart 使用 [`Future`][] 对象来实现该机制。

```js
// JavaScript
class Example {
  _getIPAddress() {
    const url = 'https://httpbin.org/ip';
    return fetch(url)
      .then(response => response.json())
      .then(responseJson => {
        const ip = responseJson.origin;
        return ip;
      });
  }
}

function main() {
  const example = new Example();
  example
    ._getIPAddress()
    .then(ip => console.log(ip))
    .catch(error => console.error(error));
}

main();
```

<?code-excerpt "lib/futures.dart"?>
```dart
// Dart
import 'dart:convert';

import 'package:http/http.dart' as http;

class Example {
  Future<String> _getIPAddress() {
    final url = Uri.https('httpbin.org', '/ip');
    return http.get(url).then((response) {
      final ip = jsonDecode(response.body)['origin'] as String;
      return ip;
    });
  }
}

void main() {
  final example = Example();
  example
      ._getIPAddress()
      .then((ip) => print(ip))
      .catchError((error) => print(error));
}
```

For more information, see the documentation on
[`Future`][] objects.

如果想了解更多相关信息，请参考 [`Future`][] 的相关文档。

#### `async` and `await`

#### `async` 和 `await`

The `async` function declaration defines an asynchronous function.

`async` 函数声明定义了一个异步执行的函数。

In JavaScript, the `async` function returns a `Promise`.
The `await` operator is used to wait for a `Promise`.

在 JavaScript 中， `async` 函数返回一个 `Promise`，
`await` 操作符用于等待 `Promise`。

```js
// JavaScript
class Example {
  async function _getIPAddress() {
    const url = 'https://httpbin.org/ip';
    const response = await fetch(url);
    const json = await response.json();
    const data = json.origin;
    return data;
  }
}

async function main() {
  const example = new Example();
  try {
    const ip = await example._getIPAddress();
    console.log(ip);
  } catch (error) {
    console.error(error);
  }
}

main();
```

In Dart, an `async` function returns a `Future`,
and the body of the function is scheduled for execution later.
The `await` operator is used to wait for a `Future`.

在 Dart 中，`async` 函数返回一个 `Future`，而函数体会在未来执行，
`await` 操作符用于等待 `Future`。

<?code-excerpt "lib/async.dart"?>
```dart
// Dart
import 'dart:convert';

import 'package:http/http.dart' as http;

class Example {
  Future<String> _getIPAddress() async {
    final url = Uri.https('httpbin.org', '/ip');
    final response = await http.get(url);
    final ip = jsonDecode(response.body)['origin'] as String;
    return ip;
  }
}

/// An async function returns a `Future`.
/// It can also return `void`, unless you use
/// the `avoid_void_async` lint. In that case,
/// return `Future<void>`.
void main() async {
  final example = Example();
  try {
    final ip = await example._getIPAddress();
    print(ip);
  } catch (error) {
    print(error);
  }
}
```

For more information, see the documentation for [async and await][].

如果想了解更多相关信息，请参考
[`async` 和 `await` 的相关文档][async and await]。

## The basics

## 基本知识

### How do I create a Flutter app?

### 如何创建一个 Flutter 应用？

To create an app using React Native,
you would run `create-react-native-app` from the command line.

如果要创建 RN 应用，
你需要在命令行里运行 `create-react-native-app`。

```console
$ create-react-native-app <projectname>
```

To create an app in Flutter, do one of the following:

要创建 Flutter 应用，完成下面其中一项即可：

* Use an IDE with the Flutter and Dart plugins installed.

  使用带有 Flutter 和 Dart 插件的 IDE。

* Use the `flutter create` command from the command line. Make sure that the
  Flutter SDK is in your PATH.

  在命令行中运行命令 `flutter create`。
  不过要提前确认 Flutter SDK 已经在系统环境变量 PATH 中定义。

```console
$ flutter create <projectname>
```

For more information, see [Getting started][], which
walks you through creating a button-click counter app.
Creating a Flutter project builds all the files that you
need to run a sample app on both Android and iOS devices.

如果想要了解更多内容，详见 [开始使用 Flutter][Getting started]，
在该页面会手把手教你创建一个点击按钮进行计数的应用。
创建一个 Flutter 项目就可以构建 Android 和 iOS 设备上运行应用所需的所有文件。

### How do I run my app?

### 我如何运行应用呢？

In React Native, you would run `npm run` or `yarn run` from the project
directory.

你可以在 RN 的项目文件夹中运行 `npm run` 或者 `yarn run` 以运行应用。

You can run Flutter apps in a couple of ways:

而想运行 Flutter 应用，你可以通过如下几个途径进行操作：

* Use the "run" option in an IDE with the Flutter and Dart plugins.

  在带有 Flutter 和 Dart 插件的 IDE 中使用 "run" 选项。

* Use `flutter run` from the project's root directory.

  在项目根目录运行 `flutter run`。

Your app runs on a connected device, the iOS simulator,
or the Android emulator.

你的应用程序会在已连接的设备、iOS 模拟器或者 Android 模拟器上运行。

For more information, see the Flutter [Getting Started][]
documentation.

如果想了解更多相关信息，可以参考 Flutter 的相关文档：
[开始使用 Flutter][Getting started]。

### How do I import widgets?

### 如何导入 widget 

In React Native, you need to import each required component.

在 RN 中，你需要导入每一个所需的组件。

```js
// React Native
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
```

In Flutter, to use widgets from the Material Design library,
import the `material.dart` package. To use iOS style widgets,
import the Cupertino library. To use a more basic widget set,
import the Widgets library.
Or, you can write your own widget library and import that.

在 Flutter 中，
如果要使用 Material Design 库里的 widget，导入 `material.dart` package。
如果要使用 iOS 风格的 widget，导入 Cupertino 库。
如果要使用更加基本的 widget，导入 Widgets 库。
或者，你可以实现自己的 widget 库并导入。

<?code-excerpt "lib/imports.dart (imports)"?>
```dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:my_widgets/my_widgets.dart';
```

Whichever widget package you import,
Dart pulls in only the widgets that are used in your app.

无论你导入哪个库，Dart 仅仅引用你应用中用到的 widget。

For more information, see the [Flutter Widget Catalog][].

如果想了解更多相关信息，可以参考 [核心 Widget 目录][Flutter Widget Catalog]。

### What is the equivalent of the React Native "Hello world!" app in Flutter?

### 在 Flutter 里有没有类似 React Native 中 "Hello world!" 应用程序？

In React Native, the `HelloWorldApp` class extends `React.Component` and
implements the render method by returning a view component.

在 RN 里，`HelloWorldApp` 继承自 `React.Component` 
并且通过返回 view 对象实现了 render 方法。

```js
// React Native
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

const App = () => {
  return (
    <View style={styles.container}>
      <Text>Hello world!</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center'
  }
});

export default App;
```

In Flutter, you can create an identical "Hello world!" app using the
`Center` and `Text` widgets from the core widget library.
The `Center` widget becomes the root of the widget tree and has one child,
the `Text` widget.

在 Flutter 中，你可以使用核心 widget 库中的
`Center` 和 `Text` widget 创建对应的「Hello world!」应用程序。
`Center` widget 是 widget 树中的根节点，而且只有 `Text` 一个子 widget。

<?code-excerpt "lib/hello_world.dart"?>
```dart
// Flutter
import 'package:flutter/material.dart';

void main() {
  runApp(
    const Center(
      child: Text('Hello, world!', textDirection: TextDirection.ltr),
    ),
  );
}
```

The following images show the Android and iOS UI for the basic Flutter
"Hello world!" app.

下面的图片展示了 Android 和 iOS 中的
基本 Flutter "Hello world!" 应用程序的界面。

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/hello-world-basic.png' alt='Hello world app on Android' title='Hello world app 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/hello-world-basic.png' alt='Hello world app on iOS' title='Hello world app 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


Now that you've seen the most basic Flutter app, the next section shows how to
take advantage of Flutter's rich widget libraries to create a modern, polished
app.

现在大家已经明白了最基本的 Flutter 应用，
接下来会告诉大家如何利用 Flutter 丰富的
widget 库来创建主流的华丽的应用程序。

### How do I use widgets and nest them to form a widget tree?

### 我如何使用 widget 并且把它们封装起来组成一个 widget 树？

In Flutter, almost everything is a widget.

在 Flutter 中，几乎任何元素都是 widget。

Widgets are the basic building blocks of an app's user interface.
You compose widgets into a hierarchy, called a widget tree.
Each widget nests inside a parent widget
and inherits properties from its parent.
Even the application object itself is a widget.
There is no separate "application" object.
Instead, the root widget serves this role.

Widget 是构建应用软件用户界面的基本元素。
你可以将 widget 按照一定的层次组合，成为 widget 树。
每个 widget 内嵌在父 widget 中，并且继承了父 widget 的属性，
甚至应用程序本身就是一个 widget。
并没有一个独立的应用程序对象。
反而根 widget 充当了这个角色。

A widget can define:

一个 widget 可以定义为：

* A structural element—like a button or menu

  类似按钮或者菜单的结构化元素

* A stylistic element—like a font or color scheme

  类似字体或者颜色方案的风格化元素

* An aspect of layout—like padding or alignment

  类似填充区或者对齐元素布局元素

The following example shows the "Hello world!" app using widgets from the
Material library. In this example, the widget tree is nested inside the
`MaterialApp` root widget.

下面的示例展示了使用 Material 库里 widget 实现的「Hello world!」应用程序。
在这个示例中，该 widget 树是包含在 `MaterialApp` root widget 里的。

<?code-excerpt "lib/widget_tree.dart"?>
```dart
// Flutter
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(title: const Text('Welcome to Flutter')),
        body: const Center(child: Text('Hello world')),
      ),
    );
  }
}
```

The following images show "Hello world!" built from Material Design widgets.
You get more functionality for free than in the basic "Hello world!" app.

下面的图片为大家展示了通过 Material Design widget 所实现的「Hello world!」应用。
你可以获得比「Hello world!」应用更多的功能。

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/hello-world.png' alt='Hello world app on Android' title='Hello world app 在 Android 上' class=''>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/hello-world.png' alt='Hello world app on iOS' title='Hello world app 在 iOS 上' class=''>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


When writing an app, you'll use two types of widgets:
[`StatelessWidget`][] or [`StatefulWidget`][].
A `StatelessWidget` is just what it sounds like&mdash;a
widget with no state. A `StatelessWidget` is created once,
and never changes its appearance.
A `StatefulWidget` dynamically changes state based on data
received, or user input.

当编写应用代码的时候，你将用到下述两种 widget：
[无状态 widget][`StatelessWidget`]
就像它的名字一样，是一个没有状态的 widget。
无状态 widget 一旦创建，就不会改变。
而 [有状态 widget][`StatefulWidget`]
会基于接收到的数据或者用户输入的数据动态改变状态。

The important difference between stateless and stateful
widgets is that `StatefulWidget`s have a `State` object
that stores state data and carries it over
across tree rebuilds, so it's not lost.

无状态 widget 和有状态 widget 之间的主要区别，
是有状态 widget 包含一个 `State` 对象会缓存状态数据，
并且 widget 树的重建也会携带该数据，因此状态不会丢失。

In simple or basic apps it's easy to nest widgets,
but as the code base gets larger and the app becomes complex,
you should break deeply nested widgets into
functions that return the widget or smaller classes.
Creating separate functions
and widgets allows you to reuse the components within the app.

在简单的或者基本的应用程序中，封装 widget 非常简单，
但是随着代码量的增加并且应用程序的功能变得更加复杂，
你应该将层级复杂的 widget 封装到函数中或者稍小一些的类。
创建独立的函数和 widget 可以让你更好地复用应用中组件。

### How do I create reusable components?

### 如何创建可复用的组件？

In React Native, you would define a function (or a class) to create a
reusable component and then use `props` methods to set
or return properties and values of the selected elements.
In the example below, the `CustomCard` function is defined
and then used inside a parent component.

在 React Native 中，你可以定义一个函数（或类）来创建一个可复用的组件，
然后使用 `props` 方法来设置或者返回属性或者所选元素的值。
在下面的示例中，`CustomCard` 类在父类中被定义和调用。

```js
// React Native
const CustomCard = ({ index, onPress }) => {
  return (
    <View>
      <Text> Card {index} </Text>
      <Button
        title="Press"
        onPress={() => onPress(index)}
      />
    </View>
  );
};

// Usage
<CustomCard onPress={this.onPress} index={item.key} />
```

In Flutter, define a class to create a custom widget and then reuse the
widget. You can also define and call a function that returns a
reusable widget as shown in the `build` function in the following example.

在 Flutter 中，定义一个类来创建一个自定义 widget 然后复用这个 widget。
你可以定义并且调用函数来返回一个可复用的 widget，
正如下面示例中 `build` 函数所示的那样。

<?code-excerpt "lib/components.dart (components)"?>
```dart
/// Flutter
class CustomCard extends StatelessWidget {
  const CustomCard({super.key, required this.index, required this.onPress});

  final int index;
  final void Function() onPress;

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Column(
        children: <Widget>[
          Text('Card $index'),
          TextButton(onPressed: onPress, child: const Text('Press')),
        ],
      ),
    );
  }
}

class UseCard extends StatelessWidget {
  const UseCard({super.key, required this.index});

  final int index;

  @override
  Widget build(BuildContext context) {
    /// Usage
    return CustomCard(
      index: index,
      onPress: () {
        print('Card $index');
      },
    );
  }
}
```

In the previous example, the constructor for the `CustomCard`
class uses Dart's curly brace syntax `{ }` to indicate [named parameters][].

在之前的示例中，`CustomCard` 类的构造函数使用 Dart 的
花括号 `{ }` 来表示 [已命名参数][named parameters]。

To require these fields, either remove the curly braces from
the constructor, or add `required` to the constructor.

如果将这些参数设定为必填参数，要么从构造函数中删掉曲括号，
或者在构造函数中加上 `required`。

The following screenshots show an example of the reusable
`CustomCard` class.

下面的截图展示了可复用的 `CustomCard` 类的示例：

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/custom-cards.png' alt='Custom cards on Android' title='Custom cards 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/custom-cards.png' alt='Custom cards on iOS' title='Custom cards 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


## Project structure and resources

## 项目结构和资源

### Where do I start writing the code?

### 该从哪开始写代码呢？

Start with the `lib/main.dart` file.
It's autogenerated when you create a Flutter app.

从 `main.dart` 文件开始。
这个文件会在你创建 Flutter 应用时自动生成。

<?code-excerpt "lib/examples.dart (main)"?>
```dart
// Dart
void main() {
  print('Hello, this is the main function.');
}
```

In Flutter, the entry point file is
`{project_name}/lib/main.dart` and execution
starts from the `main` function.

在 Flutter 中，入口文件是 `{项目目录}/lib/main.dart`
而程序执行是从 `main` 函数开始的。

### How are files structured in a Flutter app?

### Flutter 应用程序中的文件是如何组织的？

When you create a new Flutter project,
it builds the following directory structure.
You can customize it later, but this is where you start.

当你创建一个新的 Flutter 工程的时候，它会创建如下所示的文件夹结构。
你可以自定义这个结构，不过这是整个开发的起点。

<FileTree>

- <project_name>/
  - android/ // 包含 Android 相关文件。
  - build/ // 存储 iOS 和 Android 构建文件。
  - ios/ // 包含 iOS 相关文件。
  - lib/ // 包含外部可访问 Dart 源文件。
    - src/ // 包含附加源文件。
    - main.dart // Flutter 程序入口和新应用程序的起点。当你创建 Flutter 工程的时候会自动生成这些文件。你从这里开始写 Dart 代码
  - test/ // 包含自动测试文件。
  - pubspec.yaml // 包含 Flutter 应用程序的元数据。这个文件相当于 React Native 里的 package.json 文件。

</FileTree>

### Where do I put my resources and assets and how do I use them?

### 我该把资源文件放到哪并且如何调用呢？

A Flutter resource or asset is a file that is bundled and deployed
with your app and is accessible at runtime.
Flutter apps can include the following asset types:

一个 Flutter 资源就是打包到你应用程序里的一个文件并且在程序运行的时候可以访问。
Flutter 应用程序可以包含下述几种资源类型：

* Static data such as JSON files

  类似 JSON 文件的静态数据

* Configuration files

  配置文件

* Icons and images (JPEG, PNG, GIF, Animated GIF, WebP, Animated WebP, BMP,
  and WBMP)

  图标和图片（JPEG、PNG、GIF、WebP、BMP 和 WBMP）

Flutter uses the `pubspec.yaml` file,
located at the root of your project, to
identify assets required by an app.

Flutter 使用 `pubspec.yaml` 文件来确定应用程序中的资源。
该文件在工程的根目录。

```yaml
flutter:
  assets:
    - assets/my_icon.png
    - assets/background.png
```

The `assets` subsection specifies files that should be included with the app.
Each asset is identified by an explicit path
relative to the `pubspec.yaml` file, where the asset file is located.
The order in which the assets are declared does not matter.
The actual directory used (`assets` in this case) does not matter.
However, while assets can be placed in any app directory, it's a
best practice to place them in the `assets` directory.

`assets` 确定了需要包含在应用程序中的文件。
每个资源都会在 `pubspec.yaml` 中定义所存储的相对路径。
资源定义的顺序没有特殊要求。
实际的文件夹（在这里指 `assets` ）也没影响。
但是， 由于资源可以放置于程序的任何目录，
所以放在 `assets` 文件夹是比较好的。

During a build, Flutter places assets into a special archive
called the *asset bundle*, which apps read from at runtime.
When an asset's path is specified in the assets' section of `pubspec.yaml`,
the build process looks for any files
with the same name in adjacent subdirectories.
These files are also included in the asset bundle
along with the specified asset. Flutter uses asset variants
when choosing resolution-appropriate images for your app.

在构建期间，Flutter 会将资源放到一个称为 *asset bundle* 的归档文件中，
应用程序可以在运行时访问该文件。当一个资源在 `pubspec.yaml` 中被声明时，
构建进程会查询和这个文件相关的子文件夹路径，
这些文件也会被包含在 asset bundle 中。
当你为应用程序选择和屏幕显示分辨率相关的图片时，
Flutter 会使用资源变体。

In React Native, you would add a static image by placing the image file
in a source code directory and referencing it.

在 RN 中，你可以在源码文件夹中通过添加文件来
增加一个静态图片并且在代码中引用它。

```js
<Image source={require('./my-icon.png')} />
// OR
<Image
  source={{
    url: 'https://reactnative.dev/img/tiny_logo.png'
  }}
/>
```

In Flutter, add a static image to your app
using the `Image.asset` constructor in a widget's build method.

在 Flutter 中，如果要展示静态资源图片，
在 widget 的 build 方法中使用 `Image.asset` 构造即可。

<?code-excerpt "lib/examples.dart (image-asset)" replace="/return //g"?>
```dart
Image.asset('assets/background.png');
```

For more information, see [Adding Assets and Images in Flutter][].

如果想了解更多相关信息，请参考文档
[在 Flutter 中添加资源和图片][Adding Assets and Images in Flutter]。

### How do I load images over a network?

### 如何在网络中加载图片？

In React Native, you would specify the `uri` in the
`source` prop of the `Image` component and also provide the
size if needed.

在 RN 中，你可以在 `Image` 的 `source` 属性中设置 `uri` 和所需的尺寸。

In Flutter, use the `Image.network` constructor to include
an image from a URL.

在 Flutter 中，使用 `Image.network` 构造函数来实现通过地址加载图片的操作。

<?code-excerpt "lib/examples.dart (image-network)" replace="/return //g"?>
```dart
Image.network('https://docs.flutter.dev/assets/images/docs/owl.jpg');
```

### How do I install packages and package plugins?

### 我如何安装依赖 package 和 package 插件？

Flutter supports using shared packages contributed by other developers to the
Flutter and Dart ecosystems. This allows you to quickly build your app without
having to develop everything from scratch. Packages that contain
platform-specific code are known as package plugins.

Flutter 支持使用开发者向 Flutter 和 Dart 生态系统贡献的 package。
这样可以使大量开发者快速构建应用程序而无需重复造车轮。
而平台相关的 package 就被称为插件。

In React Native, you would use `yarn add {package-name}` or
`npm install --save {package-name}` to install packages
from the command line.

在 RN 中，你可以在命令行中运行 `yarn add {package-name}` 
或者 `npm install --save {package-name}` 来安装 package。

In Flutter, install a package using the following instructions:

在 Flutter 中，安装 package 需要按照如下的步骤：

1. To add the `google_sign_in` package as a dependency, run `flutter pub add`:

   运行 `flutter pub add` 将 `google_sign_in` 添加为依赖：

```console
$ flutter pub add google_sign_in
```

2. Install the package from the command line by using `flutter pub get`.
   If using an IDE, it often runs `flutter pub get` for you, or it might
   prompt you to do so.

   在命令行中输入 `flutter pub get` 来安装 package。
   如果使用 IDE，它自己会运行 `flutter pub get`，
   或者它会提示你是不是要运行该命令。

3. Import the package into your app code as shown below:

   向下面代码一样在程序中引用 package：

<?code-excerpt "lib/examples.dart (package-import)"?>
```dart
import 'package:flutter/material.dart';
```

For more information, see [Using Packages][] and
[Developing Packages & Plugins][].

如果想了解更多相关信息，请参考
[在 Flutter 里使用 Packages][Using Packages] 和
[Flutter Packages 的开发和提交][Developing Packages & Plugins]。

You can find many packages shared by Flutter developers in the
[Flutter packages][] section of [pub.dev][].

你可以在 [pub.dev][] 的 [Flutter packages][]
找到开发者们分享的 package。

## Flutter widgets

In Flutter, you build your UI out of widgets that describe what their view
should look like given their current configuration and state.

在 Flutter 中，你可以基于 widget 打造你自己的 UI，
通过 widget 当前的设置和状态会呈现相应的页面效果。

Widgets are often composed of many small,
single-purpose widgets that are nested to produce powerful effects.
For example, the `Container` widget consists of
several widgets responsible for layout, painting, positioning, and sizing.
Specifically, the `Container` widget includes the `LimitedBox`,
`ConstrainedBox`, `Align`, `Padding`, `DecoratedBox`, and `Transform` widgets.
Rather than subclassing `Container` to produce a customized effect, you can
compose these and other simple widgets in new and unique ways.

Widget 常常通过很多小的、单一功能的 widget 组成，
通过这样的封装往往能够实现很棒的效果。
比如，`Container` widget 包含多种 widget，分别负责布局、绘图、位置变化和尺寸变化。
准确的说，`Container` widget 包括 `LimitedBox`、`ConstrainedBox`、`Align`、
`Padding`、`DecoratedBox` 和 `Transform` widget。
与其继承 `Container` 来实现自定义效果，
不如直接修改这些 widget 来实现效果。

The `Center` widget is another example of how you can control the layout.
To center a widget, wrap it in a `Center` widget and then use layout
widgets for alignment, row, columns, and grids.
These layout widgets do not have a visual representation of their own.
Instead, their sole purpose is to control some aspect of another
widget's layout. To understand why a widget renders in a
certain way, it's often helpful to inspect the neighboring widgets.

`Center` widget 是另一个用于控制布局的示例。
如果要居中一个 widget，就把它封装到 `Center` widget 中，
然后使用布局 widget 来进行对齐行、列和网格。
这些布局 widget 并不可见。而他们的作用就是控制其它 widget 的布局。
如果想搞清楚为什么一个 widget 会有这样的效果，
有效的方法是研究它临近的 widget。

For more information, see the [Flutter Technical Overview][].

如果想了解更多相关信息，请参考 [Flutter 技术概览][Flutter Technical Overview]。

For more information about the core widgets from the `Widgets` package,
see [Flutter Basic Widgets][],
the [Flutter Widget Catalog][],
or the [Flutter Widget Index][].

如果想了解更多关于 Widgets package 中的核心 widget，
请参考 [基础 Flutter Widgets][Flutter Basic Widgets]、
[核心 Widget 目录][Flutter Widget Catalog]
或是 [Flutter Widget 目录][Flutter Widget Index]。

## Views

## 视图

### What is the equivalent of the `View` container?

### 与 `View` 等价容器的是什么？

In React Native, `View` is a container that supports layout with `Flexbox`,
style, touch handling, and accessibility controls.

在 RN 中， `View` 是支持 `Flexbox` 
布局、风格化、触摸事件处理和访问性控制的容器。

In Flutter, you can use the core layout widgets in the `Widgets`
library, such as [`Container`][], [`Column`][],
[`Row`][], and [`Center`][].
For more information, see the [Layout Widgets][] catalog.

在 Flutter 中，你可以使用 Widgets 库中的核心布局 widget，
比如 [`Container`][]、[`Column`][]、[`Row`][] 和 [`Center`][]。
如果想了解更多相关信息，请参考 [布局类 Widgets][Layout Widgets] 目录。

### What is the equivalent of `FlatList` or `SectionList`?

### 和 `FlatList` 或者 `SectionList` 相对应的是什么？

A `List` is a scrollable list of components arranged vertically.

`List` 是一个可以滚动的纵向排列的组件列表。

In React Native, `FlatList` or `SectionList` are used to render simple or
sectioned lists.

在 RN 中，`FlatList` 或者 `SectionList` 用于渲染简单的或者分组的列表。

```js
// React Native
<FlatList
  data={[ ... ]}
  renderItem={({ item }) => <Text>{item.key}</Text>}
/>
```

[`ListView`][] is Flutter's most commonly used scrolling widget.
The default constructor takes an explicit list of children.
[`ListView`][] is most appropriate for a small number of widgets.
For a large or infinite list, use `ListView.builder`,
which builds its children on demand and only builds
those children that are visible.

[`ListView`][] 是 Flutter 最常用的滑动 widget。
默认构造函数需要一个数据列表的参数。
[`ListView`][] 非常适合用于少量子 widget 的列表。
如果列表的元素比较多，可以使用 `ListView.builder`，
它会按需构建子项并且只创建可见的子项。

<?code-excerpt "lib/examples.dart (list-view)"?>
```dart
var data = ['Hello', 'World'];
return ListView.builder(
  itemCount: data.length,
  itemBuilder: (context, index) {
    return Text(data[index]);
  },
);
```

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/flatlist.webp' alt='Flat list on Android' title='Flat list 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/flatlist.webp' alt='Flat list on iOS' title='Flat list 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


To learn how to implement an infinite scrolling list, see the official
[`infinite_list`][infinite_list] sample.

如果要了解如何实现无限滑动列表，
请参考 [`infinite_list`][infinite_list] 示例应用。

### How do I use a Canvas to draw or paint?

### 如何使用 Canvas 绘图？

In React Native, canvas components aren't present
so third party libraries like `react-native-canvas` are used.

在 RN 中，canvas 组件是不可见的，
所以需要使用类似 `react-native-canvas` 这样的组件。

```js
// React Native
const CanvasComp = () => {
  const handleCanvas = (canvas) => {
    const ctx = canvas.getContext('2d');
    ctx.fillStyle = 'skyblue';
    ctx.beginPath();
    ctx.arc(75, 75, 50, 0, 2 * Math.PI);
    ctx.fillRect(150, 100, 300, 300);
    ctx.stroke();
  };

  return (
    <View>
      <Canvas ref={this.handleCanvas} />
    </View>
  );
}
```

In Flutter, you can use the [`CustomPaint`][]
and [`CustomPainter`][] classes to draw to the canvas.

在 Flutter 中，你可以使用 [`CustomPaint`][]
和 [`CustomPainter`][] 在画布上进行绘制。

The following example shows how to draw during the paint phase using the
`CustomPaint` widget. It implements the abstract class, `CustomPainter`,
and passes it to `CustomPaint`'s painter property.
`CustomPaint` subclasses must implement the `paint()`
and `shouldRepaint()` methods.

下面的示例代码展示了如何使用 `CustomPaint` 进行绘图。
它实现了抽象类 `CustomPainter`，
然后将它赋值给 `CustomPainter` 的 painter 属性。
`CustomPainter` 子类必须实现 `paint` 和 `shouldRepaint` 方法。

<?code-excerpt "lib/examples.dart (custom-paint)"?>
```dart
class MyCanvasPainter extends CustomPainter {
  const MyCanvasPainter();

  @override
  void paint(Canvas canvas, Size size) {
    final Paint paint = Paint()..color = Colors.amber;
    canvas.drawCircle(const Offset(100, 200), 40, paint);
    final Paint paintRect = Paint()..color = Colors.lightBlue;
    final Rect rect = Rect.fromPoints(
      const Offset(150, 300),
      const Offset(300, 400),
    );
    canvas.drawRect(rect, paintRect);
  }

  @override
  bool shouldRepaint(MyCanvasPainter oldDelegate) => false;
}

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

  @override
  Widget build(BuildContext context) {
    return const Scaffold(body: CustomPaint(painter: MyCanvasPainter()));
  }
}
```

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/canvas.png' alt='Canvas on Android' title='Canvas 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/canvas.png' alt='Canvas on iOS' title='Canvas 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


## Layouts

## 布局

### How do I use widgets to define layout properties?

### 如何使用 widget 来定义布局属性？

In React Native, most of the layout can be done with the props
that are passed to a specific component.
For example, you could use the `style` prop on the `View` component
in order to specify the flexbox properties.
To arrange your components in a column, you would specify a prop such as:
`flexDirection: 'column'`.

在 RN 中，大多数布局需要通过向指定的组件传递属性参数进行设置。
比如，你可以使用 `View` 的 `style` 来设置 flexbox 属性。
如果要整理一列的组件，你可以使用如下的属性设置：`flexDirection: “column”`。

```js
// React Native
<View
  style={{
    flex: 1,
    flexDirection: 'column',
    justifyContent: 'space-between',
    alignItems: 'center'
  }}
>
```

In Flutter, the layout is primarily defined by widgets
specifically designed to provide layout,
combined with control widgets and their style properties.

在 Flutter 中，布局主要是由专门的 widget 定义的，
它们同控制类 widget 和样式属性一起发挥功能。

For example, the [`Column`][] and [`Row`][] widgets
take an array of children and align them
vertically and horizontally respectively.
A [`Container`][] widget takes a combination of
layout and styling properties, and a
[`Center`][] widget centers its child widgets.

比如，[`Column`][] 和 [`Row`][] widget 接受一个数组的子元素
并且分别按照纵向和横向进行排列。
[`Container`][] widget 包含布局和样式属性的组合，
[`Center`][] widget 会将其自 widget 也设定居中。

<?code-excerpt "lib/layouts.dart (column)"?>
```dart
@override
Widget build(BuildContext context) {
  return Center(
    child: Column(
      children: <Widget>[
        Container(color: Colors.red, width: 100, height: 100),
        Container(color: Colors.blue, width: 100, height: 100),
        Container(color: Colors.green, width: 100, height: 100),
      ],
    ),
  );
```

Flutter provides a variety of layout widgets in its core widget library.
For example, [`Padding`][], [`Align`][], and [`Stack`][].

Flutter 在核心 widget 库中提供多种不同的布局 widget。
比如 [`Padding`][]、[`Align`][] 和 [`Stack`][]。

For a complete list, see [Layout Widgets][].

要得到完整的 widget 列表，请参考 [Layout Widgets][]。

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/basic-layout.webp' alt='Layout on Android' title='Layout 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/basic-layout.webp' alt='Layout on iOS' title='Layout 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


### How do I layer widgets?

### 如何为 widget 分层？

In React Native, components can be layered using `absolute` positioning.

在 RN 中，组件可以通过 `absolute` 划分层次。

Flutter uses the [`Stack`][]
widget to arrange children widgets in layers.
The widgets can entirely or partially overlap the base widget.

在 Flutter 中使用 [`Stack`][] widget 将子 widget 进行分层。
该 widget 可以将整体或者部分的子 widget 进行分层。

The `Stack` widget positions its children relative to the edges of its box.
This class is useful if you simply want to overlap several children widgets.

`Stack` widget 将子 widget 根据容器的边界进行布局。
如果你仅仅想把子 widget 重叠摆放的话，这个 widget 非常合适。

<?code-excerpt "lib/layouts.dart (stack)"?>
```dart
@override
Widget build(BuildContext context) {
  return Stack(
    alignment: const Alignment(0.6, 0.6),
    children: <Widget>[
      const CircleAvatar(
        backgroundImage: NetworkImage(
          'https://avatars3.githubusercontent.com/u/14101776?v=4',
        ),
      ),
      Container(color: Colors.black45, child: const Text('Flutter')),
    ],
  );
```

The previous example uses `Stack` to overlay a Container
(that displays its `Text` on a translucent black background)
on top of a `CircleAvatar`.
The Stack offsets the text using the alignment property
and `Alignment` coordinates.

上面的示例代码使用 `Stack` 将一个 Container
（`Text` 显示在一个半透明的黑色背景上）
覆盖在一个 `CircleAvatar` 上。
Stack 使用对齐属性和 Alignment 坐标微调文本。

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/stack.png' alt='Stack on Android' title='Stack 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/stack.png' alt='Stack on iOS' title='Stack 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


For more information, see the [`Stack`][] class documentation.

如果想了解更多相关信息，请参考 [`Stack`][] 类的文档。

## Styling

## 风格化

### How do I style my components?

### 如何设置组件的风格？

In React Native, inline styling and `stylesheets.create`
are used to style components.

在 RN 中，内联风格化和 `stylesheets.create` 可以用于设置组件的风格。

```js
// React Native
<View style={styles.container}>
  <Text style={{ fontSize: 32, color: 'cyan', fontWeight: '600' }}>
    This is a sample text
  </Text>
</View>

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center'
  }
});
```

In Flutter, a `Text` widget can take a `TextStyle` class
for its style property. If you want to use the same text
style in multiple places, you can create a
[`TextStyle`][] class and use it for multiple `Text` widgets.

在 Flutter 中， `Text` widget 可以接受 `TextStyle` 作为它的风格化属性。
如果你想在不同的场合使用相同的文本风格，
你可以创建一个 [`TextStyle`][] 类，
并且在多个 `Text` widget 中使用它。

<?code-excerpt "lib/examples.dart (text-style)"?>
```dart
const TextStyle textStyle = TextStyle(
  color: Colors.cyan,
  fontSize: 32,
  fontWeight: FontWeight.w600,
);

return const Center(
  child: Column(
    children: <Widget>[
      Text('Sample text', style: textStyle),
      Padding(
        padding: EdgeInsets.all(20),
        child: Icon(
          Icons.lightbulb_outline,
          size: 48,
          color: Colors.redAccent,
        ),
      ),
    ],
  ),
);
```

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/flutterstyling.webp' alt='Styling on Android' title='Styling 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/flutterstyling.webp' alt='Styling on iOS' title='Styling 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


### How do I use `Icons` and `Colors`?

### 我如何使用 `Icons` 和 `Colors` 呢？

React Native doesn't include support for icons
so third party libraries are used.

RN 并不包含默认图标，所以需要使用第三方库。

In Flutter, importing the Material library also pulls in the
rich set of [Material icons][] and [colors][].

在 Flutter 中，引用 Material 库的时候就同时引入了
[Material icons][] 和 [colors][]。

<?code-excerpt "lib/examples.dart (icon)"?>
```dart
return const Icon(Icons.lightbulb_outline, color: Colors.redAccent);
```

When using the `Icons` class,
make sure to set `uses-material-design: true` in
the project's `pubspec.yaml` file.
This ensures that the `MaterialIcons` font,
which displays the icons, is included in your app.
In general, if you intend to use the Material library,
you should include this line.

当使用 `Icons` 类时，确保在项目的 `pubspec.yaml` 文件中
设置 `uses-material-design: true`，
这样保证 `MaterialIcons` 相关字体被包含在你的应用中。
一般来说，如果你想用 Material 库的话，则需要包含这一行内容。

```yaml
name: my_awesome_application
flutter:
  uses-material-design: true
```

Flutter's [Cupertino (iOS-style)][] package provides high
fidelity widgets for the current iOS design language.
To use the `CupertinoIcons` font,
add a dependency for `cupertino_icons` in your project's
`pubspec.yaml` file.

Flutter 的 [Cupertino (iOS-style)][] package
为 iOS 设计语言提供高分辨率的 widget。
要使用 `CupertinoIcons` 字体，
在项目的 `pubspec.yaml` 文件中添加
`cupertino_icons` 的依赖即可。

```yaml
name: my_awesome_application
dependencies:
  cupertino_icons: ^1.0.8
```

To globally customize the colors and styles of components,
use `ThemeData` to specify default colors
for various aspects of the theme.
Set the theme property in `MaterialApp` to the `ThemeData` object.
The [`Colors`][] class provides colors
from the Material Design [color palette][].

要在全局范围内自定义组件的颜色和风格，
使用 `ThemeData` 为不同的主题指定默认颜色。
在 `MaterialApp` 的主题属性中设置 `ThemeData` 对象。
[`Colors`][] 类提供 Material Design [color palette][]
中所提供的颜色配置。

The following example sets the color scheme from seed to `deepPurple`
and the text selection to `red`.

下面的示例代码将主色调设置为 `deepPurple` 然后文本颜色设置为 `red`。

<?code-excerpt "lib/examples.dart (swatch)"?>
```dart
class SampleApp extends StatelessWidget {
  const SampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        textSelectionTheme: const TextSelectionThemeData(
          selectionColor: Colors.red,
        ),
      ),
      home: const SampleAppPage(),
    );
  }
}
```

### How do I add style themes?

### 如何增加风格化主题？

In React Native, common themes are defined for
components in stylesheets and then used in components.

在 React Native，常用主题都定义在样式层叠表中。

In Flutter, create uniform styling for almost everything
by defining the styling in the [`ThemeData`][]
class and passing it to the theme property in the
[`MaterialApp`][] widget.

在 Flutter 中，为所有组件创建统一风格可以在 [`ThemeData`][] 类中定义，
并将它赋值给 [`MaterialApp`][] 的主题属性。

<?code-excerpt "lib/examples.dart (theme)"?>
```dart
@override
Widget build(BuildContext context) {
  return MaterialApp(
    theme: ThemeData(primaryColor: Colors.cyan, brightness: Brightness.dark),
    home: const StylingPage(),
  );
}
```

A `Theme` can be applied even without using the `MaterialApp` widget.
The [`Theme`][] widget takes a `ThemeData` in its `data` parameter
and applies the `ThemeData` to all of its children widgets.

`Theme` 可以在不使用 `MaterialApp` widget 的情况下使用。
[`Theme`][] 接受一个 `ThemeData` 参数，
并且将 `ThemeData` 应用于它的全部子 widget。

<?code-excerpt "lib/examples.dart (theme-data)"?>
```dart
@override
Widget build(BuildContext context) {
  return Theme(
    data: ThemeData(primaryColor: Colors.cyan, brightness: brightness),
    child: Scaffold(
      backgroundColor: Theme.of(context).primaryColor,
      //...
    ),
  );
}
```

## State management

## 状态管理

State is information that can be read synchronously
when a widget is built or information
that might change during the lifetime of a widget.
To manage app state in Flutter,
use a [`StatefulWidget`][] paired with a State object.

当 widget 被创建或者在 widget 的生命周期中有信息发生改变时所产生的信息叫做状态。
要在 Flutter 中管理应用程序的状态，使用
[`StatefulWidget`][] 和 State 对象。

For more information on ways to approach managing state in Flutter,
see [State management][].

欲知更多关于 Flutter 的状态管理相关的内容，请参访
[状态管理文档][State management] 页面。

### The StatelessWidget

### 管理 StatelessWidget widget

A `StatelessWidget` in Flutter is a widget
that doesn't require a state change&mdash;
it has no internal state to manage.

`StatelessWidget` 在 Flutter 中是一个不需要状态改变的 widget，它没有内部的状态。

Stateless widgets are useful when the part of the user interface
you are describing does not depend on anything other than the
configuration information in the object itself and the
[`BuildContext`][] in which the widget is inflated.

当你展现给用户的界面并不依赖其它任何配置信息并且使用
[`BuildContext`][] 来解析 widget，则需要使用无状态 widget。

[`AboutDialog`][], [`CircleAvatar`][], and [`Text`][] are examples
of stateless widgets that subclass [`StatelessWidget`][].

[`AboutDialog`][]、[`CircleAvatar`][] 和 [`Text`][] 是
[`StatelessWidget`][] 的子类，并且是很典型的无状态 widget。

<?code-excerpt "lib/stateless.dart"?>
```dart
import 'package:flutter/material.dart';

void main() => runApp(
  const MyStatelessWidget(
    text: 'StatelessWidget Example to show immutable data',
  ),
);

class MyStatelessWidget extends StatelessWidget {
  const MyStatelessWidget({super.key, required this.text});

  final String text;

  @override
  Widget build(BuildContext context) {
    return Center(child: Text(text, textDirection: TextDirection.ltr));
  }
}
```

The previous example uses the constructor of the `MyStatelessWidget`
class to pass the `text`, which is marked as `final`.
This class extends `StatelessWidget`&mdash;it contains immutable data.

在上面的例子中，你用到了 `MyStatelessWidget` 类的构造函数来传递 `text`。
并且它被标记为 `final`。该类继承了 `StatelessWidget`，它包含不可变的数据。

The `build` method of a stateless widget is typically called
in only three situations:

无状态 widget 的 `build` 方法通常只有在三种情况下会被调用：

* When the widget is inserted into a tree

  当 widget 被插入到 widget 树中；

* When the widget's parent changes its configuration

  当 widget 的父 widget 改变了配置；

* When an [`InheritedWidget`][] it depends on, changes

  当所依赖的 [`InheritedWidget`][] 发生了改变。

### The StatefulWidget

### StatefulWidget widget

A [`StatefulWidget`][] is a widget that changes state.
Use the `setState` method to manage the
state changes for a `StatefulWidget`.
A call to `setState()` tells the Flutter
framework that something has changed in a state,
which causes an app to rerun the `build()` method
so that the app can reflect the change.

[`StatefulWidget`][] 是携带状态变化的 widget。
通过调用 `setState` 方法可以管理 `StatefulWidget` 的状态。
当调用 `setState()` 的时候，程序会通知 Flutter 框架有状态发生了改变，
然后会重新运行 `build()` 方法来更新应用的状态。

_State_ is information that can be read synchronously when a widget
is built and might change during the lifetime of the widget.
It's the responsibility of the widget implementer to ensure that
the state object is promptly notified when the state changes.
Use `StatefulWidget` when a widget can change dynamically.
For example, the state of the widget changes by typing into a form,
or moving a slider.
Or, it can change over time—perhaps a data feed updates the UI.

**状态** 是在 widget 被创建期间可以被同步读取的信息，
并且在 widget 的生命周期中会发生改变。
实现该 widget 的时候要注意保证党状态发生改变的时候程序能够获得相应的提醒。
当 widget 能够动态改变的时候，请使用 `StatefulWidget`。
比如，某个 widget 会随着用户填写表单或者移动滑块的时候发生改变。
亦或者随着数据源更新的时候发生改变。

[`Checkbox`][], [`Radio`][], [`Slider`][], [`InkWell`][],
[`Form`][], and [`TextField`][]
are examples of stateful widgets that subclass
[`StatefulWidget`][].

[`Checkbox`][]、[`Radio`][]、[`Slider`][]、[`InkWell`][]、
[`Form`][]、和 [`TextField`][] 都是有状态的 widget，是
[`StatefulWidget`][] 的子类。

The following example declares a `StatefulWidget`
that requires a `createState()` method.
This method creates the state object that manages the widget's state,
`_MyStatefulWidgetState`.

下面的示例代码声明了一个 `StatefulWidget`，需要实现 `createState()` 方法。
该方法创建一个对象来管理 widget 的状态，也就是 `_MyStatefulWidgetState`。

<?code-excerpt "lib/stateful.dart (stateful-widget)"?>
```dart
class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({super.key, required this.title});

  final String title;

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
```

The following state class, `_MyStatefulWidgetState`,
implements the `build()` method for the widget.
When the state changes, for example, when the user toggles
the button, `setState()` is called with the new toggle value.
This causes the framework to rebuild this widget in the UI.

下面的状态类，`_MyStatefulWidgetState`，实现了 `build()` 方法。
当状态发生改变的时候，比如说用户点击了开关按钮，
这时 `setState` 就会被调用，并且将新的开关状态传进来。
这就会使整体框架重构这个 widget。

<?code-excerpt "lib/stateful.dart (stateful-widget-state)"?>
```dart
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  bool showText = true;
  bool toggleState = true;
  Timer? t2;

  void toggleBlinkState() {
    setState(() {
      toggleState = !toggleState;
    });
    if (!toggleState) {
      t2 = Timer.periodic(const Duration(milliseconds: 1000), (t) {
        toggleShowText();
      });
    } else {
      t2?.cancel();
    }
  }

  void toggleShowText() {
    setState(() {
      showText = !showText;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          children: <Widget>[
            if (showText)
              const Text('This execution will be done before you can blink.'),
            Padding(
              padding: const EdgeInsets.only(top: 70),
              child: ElevatedButton(
                onPressed: toggleBlinkState,
                child: toggleState
                    ? const Text('Blink')
                    : const Text('Stop Blinking'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
```

### What are the StatefulWidget and StatelessWidget best practices?

### StatefulWidget 和 StatelessWidget 的最佳实践是什么？

Here are a few things to consider when designing your widget.

下面有一些设计原则供大家参考。

1. Determine whether a widget should be
   a `StatefulWidget` or a `StatelessWidget`.

   确定一个 widget 应该是 `StatefulWidget` 还是 `StatelessWidget`。

In Flutter, widgets are either Stateful or Stateless—depending on whether
they depend on a state change.

在 Flutter 中， widget 要么是有状态的，要么是无状态的。
这取决于 widget 是否依赖状态的改变。

* If a widget changes&mdash;the user interacts with it or
  a data feed interrupts the UI, then it's *Stateful*.

  如果一个 widget 发生了改变，而它所处的用户界面或者数据中断了 UI，
  那么该 widget 就是 **有状态** 的。

* If a widget is final or immutable, then it's *Stateless*.

  如果一个 widget 是 final 类型或者 immutable 类型的，
  那么该 widget 是 **无状态** 的。

2. Determine which object manages the widget's state (for a `StatefulWidget`).

   确定哪个对象来控制 widget 的状态（针对 `StatefulWidget`）。

In Flutter, there are three primary ways to manage state:

在 Flutter 中，有三种途径来管理状态：

* The widget manages its own state

  widget 管理它的自身状态

* The parent widget manages the widget's state

  由其父 widget 管理 widget 状态

* A mix-and-match approach

  通过混搭的方式

When deciding which approach to use, consider the following principles:

当决定了使用哪个途径后，要考虑下述的几个原则：

* If the state in question is user data, for example the checked or unchecked
  mode of a checkbox, or the position of a slider, then the state is best managed
  by the parent widget.

  如果状态信息是用户数据，比如复选框是被勾选还是未被勾选，或者滑块的位置，
  那么父 widget 会很好的处理当前 widget 的状态。

* If the state in question is user data,
  for example the checked or unchecked mode of a checkbox,
  or the position of a slider, then the state is best managed
  by the parent widget.
* If the state in question is aesthetic, for example an animation,
  then the widget itself best manages the state.

  如果状态是和外观效果相关的，比如动画，那么 widget 自己会处理状态的变化。

* When in doubt, let the parent widget manage the child widget's state.

  如果无法确定，那么父 widget 会处理子 widget 的状态。

3. Subclass StatefulWidget and State.

   继承 `StatefulWidget` 和 `State`。

The `MyStatefulWidget` class manages its own state&mdash;it extends
`StatefulWidget`, it overrides the `createState()`
method to create the `State` object,
and the framework calls `createState()` to build the widget.
In this example, `createState()` creates an instance of
`_MyStatefulWidgetState`, which
is implemented in the next best practice.

`MyStatefulWidget` 类管理它自身的状态&mdash;&mdash
它继承自 `StatefulWidget`，重写了 `createState()` 方法。
该方法创建了 `State` 对象，同时框架会调用
`createState()` 方法来构建 widget。
在这个例子中，`createState()` 方法创建了一个 
`_MyStatefulWidgetState` 实例。
下面的最佳实践中也实现了类似的方法。

<?code-excerpt "lib/best_practices.dart (create-state)" replace="/return const Text\('Hello World!'\);/\/\/.../g"?>
```dart
class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({super.key, required this.title});

  final String title;
  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  @override
  Widget build(BuildContext context) {
    //...
  }
}
```

4. Add the StatefulWidget into the widget tree.

   将 StatefulWidget 添加到 widget 树中

Add your custom `StatefulWidget` to the widget tree
in the app's build method.

将你自定义的 `StatefulWidget` 通过应用程序的
build 方法添加到 widget 树中。

<?code-excerpt "lib/best_practices.dart (use-stateful-widget)"?>
```dart
class MyStatelessWidget extends StatelessWidget {
  // This widget is the root of your application.
  const MyStatelessWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyStatefulWidget(title: 'State Change Demo'),
    );
  }
}
```

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/state-change.webp' alt='State change on Android' title='State change 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/state-change.webp' alt='State change on iOS' title='State change 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


## Props

In React Native, most components can be customized when they are
created with different parameters or properties, called `props`.
These parameters can be used in a child component using `this.props`.

在 RN 中，大多数组件都可以在创建的时候通过不同的参数或者属性来自定义，
叫做 `props`。这些参数可以在子组件中通过 `this.props` 进行调用。

```js
// React Native
const CustomCard = ({ index, onPress }) => {
  return (
    <View>
      <Text> Card {index} </Text>
      <Button
        title='Press'
        onPress={() => onPress(index)}
      />
    </View>
  );
};

const App = () => {
  const onPress = (index) => {
    console.log('Card ', index);
  };

  return (
    <View>
      <FlatList
        data={[ /* ... */ ]}
        renderItem={({ item }) => (
          <CustomCard onPress={onPress} index={item.key} />
        )}
      />
    </View>
  );
};
```

In Flutter, you assign a local variable or function marked
`final` with the property received in the parameterized constructor.

在 Flutter 中，你可以将构造函数中的参数值赋值
给标记为 `final` 的本地变量或者函数。

<?code-excerpt "lib/components.dart (components)"?>
```dart
/// Flutter
class CustomCard extends StatelessWidget {
  const CustomCard({super.key, required this.index, required this.onPress});

  final int index;
  final void Function() onPress;

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Column(
        children: <Widget>[
          Text('Card $index'),
          TextButton(onPressed: onPress, child: const Text('Press')),
        ],
      ),
    );
  }
}

class UseCard extends StatelessWidget {
  const UseCard({super.key, required this.index});

  final int index;

  @override
  Widget build(BuildContext context) {
    /// Usage
    return CustomCard(
      index: index,
      onPress: () {
        print('Card $index');
      },
    );
  }
}
```

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/modular.png' alt='Cards on Android' title='Cards 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/modular.png' alt='Cards on iOS' title='Cards 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


## Local storage

## 本地存储

If you don't need to store a lot of data, and it doesn't require
structure, you can use `shared_preferences` which allows you to
read and write persistent key-value pairs of primitive data
types: booleans, floats, ints, longs, and strings.

如果你不需要在本地存储太多数据同时也不需要存储结构化数据，
那么你可以使用 `shared_preferences`，通过它来读写一些原始数据类型键值对，
数据类型包括布尔、浮点、整数、长精度和字符串。

### How do I store persistent key-value pairs that are global to the app?

### 如何存储在应用程序中全局有效的键值对？

In React Native, you use the `setItem` and `getItem` functions
of the `AsyncStorage` component to store and retrieve data
that is persistent and global to the app.

在 React Native，可以使用 `AsyncStorage` 中的
`setItem` 和 `getItem` 函数来存储和读取应用程序中的全局数据。

```js
// React Native
const [counter, setCounter] = useState(0)
...
await AsyncStorage.setItem( 'counterkey', json.stringify(++this.state.counter));
AsyncStorage.getItem('counterkey').then(value => {
  if (value != null) {
    setCounter(value);
  }
});
```

In Flutter, use the [`shared_preferences`][] plugin to
store and retrieve key-value data that is persistent and global
to the app. The `shared_preferences` plugin wraps
`NSUserDefaults` on iOS and `SharedPreferences` on Android,
providing a persistent store for simple data.

在 Flutter 中，使用 [`shared_preferences`][] 插件来
存储和访问应用程序内全局有效的键值对数据。
`shared_preferences` 插件封装了 iOS 中的 `NSUserDefaults` 和
Android 中的 `SharedPreferences` 来实现简单数据的持续存储。

To add the `shared_preferences` package as a dependency, run `flutter pub add`:

运行 `flutter pub add` 将 `shared_preferences` 添加为依赖：

```console
$ flutter pub add shared_preferences
```

<?code-excerpt "lib/examples.dart (shared-prefs)"?>
```dart
import 'package:shared_preferences/shared_preferences.dart';
```

To implement persistent data, use the setter methods
provided by the `SharedPreferences` class.
Setter methods are available for various primitive
types, such as `setInt`, `setBool`, and `setString`.
To read data, use the appropriate getter method provided
by the `SharedPreferences` class. For each
setter there is a corresponding getter method,
for example, `getInt`, `getBool`, and `getString`.

要实现持久数据存储，使用 `SharedPreferences` 类提供的 setter 方法即可。
Setter 方法适用于多种原始类型数据，
比如 `setInt`、`setBool`、和 `setString`。
要读取数据，使用 `SharedPreferences` 类中相应的 getter 方法。
每一个 setter 方法都有对应的 getter 方法，
比如，`getInt`、`getBool` 和 `getString`。

<?code-excerpt "lib/examples.dart (shared-prefs-update)"?>
```dart
Future<void> updateCounter() async {
  final prefs = await SharedPreferences.getInstance();
  int? counter = prefs.getInt('counter');
  if (counter is int) {
    await prefs.setInt('counter', ++counter);
  }
  setState(() {
    _counter = counter;
  });
}
```

## Routing

## 路径

Most apps contain several screens for displaying different
types of information. For example, you might have a product
screen that displays images where users could tap on a product
image to get more information about the product on a new screen.

大多数应用都会包含多个页面来显示不同类型的数据。
比如，你有一个页面展示商品列表，
用户可以通过点击其中的任意一个商品，
在另外一个页面查看该商品的详细信息。

In Android, new screens are new Activities.
In iOS, new screens are new ViewControllers. In Flutter,
screens are just Widgets! And to navigate to new
screens in Flutter, use the Navigator widget.

在 Android 中，新的页面是 Activity。 在 iOS 中，
新的页面是 ViewController。在 Flutter 中，页面也只是 widget，
如果在 Flutter 中要切换页面，使用 Navigator widget 即可。

### How do I navigate between screens?

### 如何在页面之间进行切换？

In React Native, there are three main navigators:
StackNavigator, TabNavigator, and DrawerNavigator.
Each provides a way to configure and define the screens.

在 RN 中，有三种主要的导航 widget ：
StackNavigator、TabNavigator 和 DrawerNavigator。
每个都提供了配置和定义页面的方法。

```js
// React Native
const MyApp = TabNavigator(
  { Home: { screen: HomeScreen }, Notifications: { screen: tabNavScreen } },
  { tabBarOptions: { activeTintColor: '#e91e63' } }
);
const SimpleApp = StackNavigator({
  Home: { screen: MyApp },
  stackScreen: { screen: StackScreen }
});
export default (MyApp1 = DrawerNavigator({
  Home: {
    screen: SimpleApp
  },
  Screen2: {
    screen: drawerScreen
  }
}));
```

In Flutter, there are two main widgets used to navigate between screens:

在 Flutter 中，有两种主要的 widget 实现页面之间的切换：

* A [`Route`][] is an abstraction for an app screen or page.

  [`Route`][] 是应用程序页面的一个抽象类。

* A [`Navigator`][] is a widget that manages routes.

  [`Navigator`][] 是管理页面路径的 widget。

A `Navigator` is defined as a widget that manages a set of child
widgets with a stack discipline. The navigator manages a stack
of `Route` objects and provides methods for managing the stack,
like [`Navigator.push`][] and [`Navigator.pop`][].
A list of routes might be specified in the [`MaterialApp`][] widget,
or they might be built on the fly, for example, in hero animations.
The following example specifies named routes in the `MaterialApp` widget.

`Navigator` 以堆栈的方式管理子 widget。
它的堆栈里存储的是 `Route` 对象，并且提供方法管理整个堆栈，
比如 [`Navigator.push`][] 和 [`Navigator.pop`][]。
路径列表需要在 [`MaterialApp`][] 中指定。
或者在页面切换的时候进行构建，比如 hero 动画。
下面的例子在 `MaterialApp` widget 中指定了页面切换路径。

:::note

Named routes are no longer recommended for most
applications. For more information, see
[Limitations][] in the [navigation overview][] page.

针对大多数的应用情况，我们不再推荐使用命名的路由 (Named routes)，
了解更多信息，请参考导航概览中的 [受限情况][Limitations] 部分。

:::

[Limitations]: /ui/navigation#limitations
[navigation overview]: /ui/navigation

<?code-excerpt "lib/navigation.dart (navigator)"?>
```dart
class NavigationApp extends StatelessWidget {
  // This widget is the root of your application.
  const NavigationApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      //...
      routes: <String, WidgetBuilder>{
        '/a': (context) => const UsualNavScreen(),
        '/b': (context) => const DrawerNavScreen(),
      },
      //...
    );
  }
}
```

To navigate to a named route, the [`Navigator.of()`][]
method is used to specify the `BuildContext`
(a handle to the location of a widget in the widget tree).
The name of the route is passed to the `pushNamed` function to
navigate to the specified route.

要切换到一个已命名的路径，[`Navigator.of()`][] 方法被用于
指定 `BuildContext`（该对象可以定位到 widget 树中的一个具体的 widget）。
路径的名称传递到 `pushNamed` 函数来切换至指定的路径。

<?code-excerpt "lib/navigation.dart (push-named)"?>
```dart
Navigator.of(context).pushNamed('/a');
```

You can also use the push method of `Navigator` which
adds the given [`Route`][] to the history of the
navigator that most tightly encloses the given [`BuildContext`][],
and transitions to it. In the following example,
the [`MaterialPageRoute`][] widget is a modal route that
replaces the entire screen with a platform-adaptive
transition. It takes a [`WidgetBuilder`][] as a required parameter.

你可以使用 `Navigator` 中的 push 方法添加
[`Route`][] 到 navigator 的历史队列中，
其中包含 [`BuildContext`][] 并且可以切换到指定页面。
在下面的例子中，[`MaterialPageRoute`][] widget 是一个模式化路径，
可以将整个页面通过平台自适应切换方式进行切换。
它需要一个 [`WidgetBuilder`][] 参数。

<?code-excerpt "lib/navigation.dart (navigator-push)"?>
```dart
Navigator.push(
  context,
  MaterialPageRoute<void>(builder: (context) => const UsualNavScreen()),
);
```

### How do I use tab navigation and drawer navigation?

### 如何使用 tab 导航和 drawer 导航？ 

In Material Design apps, there are two primary options
for Flutter navigation: tabs and drawers.
When there is insufficient space to support tabs, drawers
provide a good alternative.

在 Material Design 应用程序中，
Flutter 的导航形式主要有两种：tab 和 drawer。
如果没有足够的 widget 可以容纳 tab，drawer 就是个不错的选择。

#### Tab navigation

#### Tab 导航

In React Native, `createBottomTabNavigator`
and `TabNavigation` are used to
show tabs and for tab navigation.

在 RN 中，`createBottomTabNavigator`
和 `TabNavigation` 用来显示 tab 和 tab 导航。

```js
// React Native
import { createBottomTabNavigator } from 'react-navigation';

const MyApp = TabNavigator(
  { Home: { screen: HomeScreen }, Notifications: { screen: tabNavScreen } },
  { tabBarOptions: { activeTintColor: '#e91e63' } }
);
```

Flutter provides several specialized widgets for drawer and
tab navigation:

Flutter 针对 drawer 和 tab 导航提供几种专用的 widget：

[`TabController`][]
<br> Coordinates the tab selection between a `TabBar`
  and a `TabBarView`.

[`TabController`][]
<br> 将 tab 与 TabBar 和 TabBarView 结合起来使用。

[`TabBar`][]
<br> Displays a horizontal row of tabs.

[`TabBar`][]
<br> 水平显示一行 tab。

[`Tab`][]
<br> Creates a material design TabBar tab.

[`Tab`][]
<br> 创建一个 material design 风格的 TabBar 中的 tab。

[`TabBarView`][]
<br> Displays the widget that corresponds to the currently selected tab.

[`TabBarView`][]
<br> 显示目前所选 tab 所对应的 widget。

<?code-excerpt "lib/navigation.dart (tab-nav)"?>
```dart
class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
  late TabController controller = TabController(length: 2, vsync: this);

  @override
  Widget build(BuildContext context) {
    return TabBar(
      controller: controller,
      tabs: const <Tab>[
        Tab(icon: Icon(Icons.person)),
        Tab(icon: Icon(Icons.email)),
      ],
    );
  }
}
```


A `TabController` is required to coordinate the tab selection
between a `TabBar` and a `TabBarView`.
The `TabController` constructor `length` argument is the total
number of tabs. A `TickerProvider` is required to trigger
the notification whenever a frame triggers a state change.
The `TickerProvider` is `vsync`. Pass the
`vsync: this` argument to the `TabController` constructor
whenever you create a new `TabController`.

要将 tab 选项与 `TabBar` 和 `TabBarView` 结合起来使用就需要 `TabController`。
`TabController` 的构造函数中的 `length` 参数定义了 tab 的总数。
当状态变化时，需要使用 `TickerProvider` 来触发通知。
`TickerProvider` 是 `vsync`，当你需要创建新的 `TabController` 时，
将 `vsync: this` 作为构造函数的参数即可。

The [`TickerProvider`][] is an interface implemented
by classes that can vend [`Ticker`][] objects.
Tickers can be used by any object that must be notified whenever a
frame triggers, but they're most commonly used indirectly via an
[`AnimationController`][]. `AnimationController`s
need a `TickerProvider` to obtain their `Ticker`.
If you are creating an AnimationController from a State,
then you can use the [`TickerProviderStateMixin`][]
or [`SingleTickerProviderStateMixin`][]
classes to obtain a suitable `TickerProvider`.

[`TickerProvider`][] 接口可以用于生成 [`Ticker`][] 对象。
当有对象被触发通知后会用到 Tickers，
不过它通常都是被 [`AnimationController`][] 间接调用。
`AnimationController` 需要 `TickerProvider` 来获得对应的 `Ticker`。 
如果你通过 State 创建了一个 AnimationController，
那么你就可以使用 [`TickerProviderStateMixin`][]
或者 [`SingleTickerProviderStateMixin`][] 
来获得对应的 `TickerProvider`。

The [`Scaffold`][] widget wraps a new `TabBar` widget and
creates two tabs. The `TabBarView` widget
is passed as the `body` parameter of the `Scaffold` widget.
All screens corresponding to the `TabBar` widget's tabs are
children to the `TabBarView` widget along with the same `TabController`.

[`Scaffold`][] 封装了一个新的 `TabBar` widget，其中包含两个 tab。
`TabBarView` 作为 `body` 参数传递到 `Scaffold` 中。
所有和 `TabBar` 中的 tab 相关的页面均是 `TabBarView` 的子 widget，
并且都对应同一个 `TabController`。

<?code-excerpt "lib/navigation.dart (navigation-home-page-state)"?>
```dart
class _NavigationHomePageState extends State<NavigationHomePage>
    with SingleTickerProviderStateMixin {
  late TabController controller = TabController(length: 2, vsync: this);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: Material(
        color: Colors.blue,
        child: TabBar(
          tabs: const <Tab>[
            Tab(icon: Icon(Icons.person)),
            Tab(icon: Icon(Icons.email)),
          ],
          controller: controller,
        ),
      ),
      body: TabBarView(
        controller: controller,
        children: const <Widget>[HomeScreen(), TabScreen()],
      ),
    );
  }
}
```

#### Drawer navigation

#### Drawer 导航

In React Native, import the needed react-navigation packages and then use
`createDrawerNavigator` and `DrawerNavigation`.

在 RN 中，导入所需的 react-navigation package，
然后使用 `createDrawerNavigator` 和 `DrawerNavigation` 实现。

```js
// React Native
export default (MyApp1 = DrawerNavigator({
  Home: {
    screen: SimpleApp
  },
  Screen2: {
    screen: drawerScreen
  }
}));
```

In Flutter, we can use the `Drawer` widget in combination with a
`Scaffold` to create a layout with a Material Design drawer.
To add a `Drawer` to an app, wrap it in a `Scaffold` widget.
The `Scaffold` widget provides a consistent
visual structure to apps that follow the
[Material Design][] guidelines. It also supports
special Material Design components,
such as `Drawers`, `AppBars`, and `SnackBars`.

在 Flutter 中，我们可以结合 `Drawer` 和 `Scaffold`
一起使用来实现 Material Design 风格的 drawer 布局。
如果要在应用程序中添加 `Drawer`， 可以将它封装在 `Scaffold` widget 中。
`Scaffold` widget 提供了一种一致的界面风格，
它遵循 [Material Design][] 的设计原则。
同时它还支持一些特殊的 Material Design 组件，
比如 `Drawers`，`AppBars`， 和 `SnackBars`。

The `Drawer` widget is a Material Design panel that slides
in horizontally from the edge of a `Scaffold` to show navigation
links in an application. You can
provide a [`ElevatedButton`][], a [`Text`][] widget,
or a list of items to display as the child to the `Drawer` widget.
In the following example, the [`ListTile`][]
widget provides the navigation on tap.

`Drawer` 就是一个 Material Design 窗格，
它可以从 `Scaffold` 边缘水平滑动显示应用程序的导航选项。
你可以在里面添加 [`ElevatedButton`][] 或 [`Text`][] 。
或者添加一个列表的元素作为 `Drawer` 的子 widget。
在下面的例子中，[`ListTile`][] 提供了点击导航。

<?code-excerpt "lib/examples.dart (drawer)"?>
```dart
@override
Widget build(BuildContext context) {
  return Drawer(
    elevation: 20,
    child: ListTile(
      leading: const Icon(Icons.change_history),
      title: const Text('Screen2'),
      onTap: () {
        Navigator.of(context).pushNamed('/b');
      },
    ),
  );
}
```

The `Scaffold` widget also includes an `AppBar` widget that automatically
displays an appropriate IconButton to show the `Drawer` when a Drawer is
available in the `Scaffold`. The `Scaffold` automatically handles the
edge-swipe gesture to show the `Drawer`.

`Scaffold` 还包含一个 `AppBar`。
它会自动显示一个图标按钮来表明 `Scaffold` 中有一个`Drawer`。
`Scaffold` 会自动处理边缘的滑动手势来显示 `Drawer`。

<?code-excerpt "lib/examples.dart (scaffold)"?>
```dart
@override
Widget build(BuildContext context) {
  return Scaffold(
    drawer: Drawer(
      elevation: 20,
      child: ListTile(
        leading: const Icon(Icons.change_history),
        title: const Text('Screen2'),
        onTap: () {
          Navigator.of(context).pushNamed('/b');
        },
      ),
    ),
    appBar: AppBar(title: const Text('Home')),
    body: Container(),
  );
}
```

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/navigation.webp' alt='Navigation on Android' title='Navigation 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/navigation.webp' alt='Navigation on iOS' title='Navigation 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


## Gesture detection and touch event handling

## 手势检测和触摸事件处理

To listen for and respond to gestures,
Flutter supports taps, drags, and scaling.
The gesture system in Flutter has two separate layers.
The first layer includes raw pointer events,
which describe the location and movement of pointers,
(such as touches, mice, and styli movements), across the screen.
The second layer includes gestures
that describe semantic actions
and consist of one or more pointer movements.

Flutter 支持点击、拖拽和缩放手势来监听和相应手势操作。
Flutter 中的手势处理有两个独立的层。第一层是指针事件，
指针事件定义了指针在屏幕上的位置和动作，比如触摸、鼠标和触摸笔。
第二层指手势，主要是语义层面的动作，里面包含一种或者多种指针动作。

### How do I add a click or press listeners to a widget?

### 如何为 widget 添加点击或者按压的监听器？

In React Native, listeners are added to components
using `PanResponder` or the `Touchable` components.

在 RN 中，使用 `PanResponder` 或者 `Touchable` 组件来添加监听器。

```js
// React Native
<TouchableOpacity
  onPress={() => {
    console.log('Press');
  }}
  onLongPress={() => {
    console.log('Long Press');
  }}
>
  <Text>Tap or Long Press</Text>
</TouchableOpacity>
```

For more complex gestures and combining several touches into
a single gesture, [`PanResponder`][] is used.

对于更加复杂手势以及将多个触摸添加到单独的一个手势中，
可以使用 [`PanResponder`][]。

```js
// React Native
const App = () => {
  const panResponderRef = useRef(null);

  useEffect(() => {
    panResponderRef.current = PanResponder.create({
      onMoveShouldSetPanResponder: (event, gestureState) =>
        !!getDirection(gestureState),
      onPanResponderMove: (event, gestureState) => true,
      onPanResponderRelease: (event, gestureState) => {
        const drag = getDirection(gestureState);
      },
      onPanResponderTerminationRequest: (event, gestureState) => true
    });
  }, []);

  return (
    <View style={styles.container} {...panResponderRef.current.panHandlers}>
      <View style={styles.center}>
        <Text>Swipe Horizontally or Vertically</Text>
      </View>
    </View>
  );
};
```

In Flutter, to add a click (or press) listener to a widget,
use a button or a touchable widget that has an `onPress: field`.
Or, add gesture detection to any widget by wrapping it
in a [`GestureDetector`][].

在 Flutter 中，要为 widget 添加点击或者按压监听器，
使用带有 `onPress: field` 的按钮或者可触摸 widget 即可。
或者，用任何 widget 封装 [`GestureDetector`][]，在其中添加手势检测。

<?code-excerpt "lib/examples.dart (gesture-detector)"?>
```dart
@override
Widget build(BuildContext context) {
  return GestureDetector(
    child: Scaffold(
      appBar: AppBar(title: const Text('Gestures')),
      body: const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Tap, Long Press, Swipe Horizontally or Vertically'),
          ],
        ),
      ),
    ),
    onTap: () {
      print('Tapped');
    },
    onLongPress: () {
      print('Long Pressed');
    },
    onVerticalDragEnd: (value) {
      print('Swiped Vertically');
    },
    onHorizontalDragEnd: (value) {
      print('Swiped Horizontally');
    },
  );
}
```

For more information, including a list of
Flutter `GestureDetector` callbacks,
see the [GestureDetector class][].

如果想要了解更多详细内容，包括 Flutter 的
`GestureDetector` 回调函数的列表，
请查看页面 [GestureDetector 类][GestureDetector class]。

[GestureDetector class]: https://api.flutter-io.cn/flutter/widgets/GestureDetector-class.html#instance-properties

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/flutter-gestures.webp' alt='Gestures on Android' title='Gestures 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/flutter-gestures.webp' alt='Gestures on iOS' title='Gestures 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


## Making HTTP network requests

## 发起 HTTP 网络请求

Fetching data from the internet is common for most apps. And in Flutter,
the `http` package provides the simplest way to fetch data from the internet.

对于大多数应用程序来说都需要从互联网上获取数据。
在 Flutter 中，`http` package 提供了从互联网获取数据的最简单的途径。

### How do I fetch data from API calls?

### 如何通过 API 调用来获得数据呢？

React Native provides the Fetch API for networking—you make a fetch request
and then receive the response to get the data.

RN 提供 Fetch API 实现网络编程，
你可以发起请求，然后接收响应来获得数据。

```js
// React Native
const [ipAddress, setIpAddress] = useState('')

const _getIPAddress = () => {
  fetch('https://httpbin.org/ip')
    .then(response => response.json())
    .then(responseJson => {
      setIpAddress(responseJson.origin);
    })
    .catch(error => {
      console.error(error);
    });
};
```

Flutter uses the `http` package.

Flutter 使用 `http` package。

To add the `http` package as a dependency, run `flutter pub add`:

运行 `flutter pub add` 将 `http` 添加为依赖：

```console
$ flutter pub add http
```

Flutter uses the [`dart:io`][] core HTTP support client.
To create an HTTP Client, import `dart:io`.

Flutter 使用 [`dart:io`][] 提供核心的 HTTP 客户端支持，
要创建一个 HTTP 客户端，引用 `dart:io`。

<?code-excerpt "lib/examples.dart (import-dart-io)"?>
```dart
import 'dart:io';
```

The client supports the following HTTP operations:
GET, POST, PUT, and DELETE.

客户端支持如下所列的 HTTP 操作：GET, POST, PUT 和 DELETE。

<?code-excerpt "lib/examples.dart (http)"?>
```dart
final Uri url = Uri.parse('https://httpbin.org/ip');
final HttpClient httpClient = HttpClient();

Future<void> getIPAddress() async {
  final request = await httpClient.getUrl(url);
  final response = await request.close();
  final responseBody = await response.transform(utf8.decoder).join();
  final ip = jsonDecode(responseBody)['origin'] as String;
  setState(() {
    _ipAddress = ip;
  });
}
```

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/api-calls.webp' alt='API calls on Android' title='API calls 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/api-calls.webp' alt='API calls on iOS' title='API calls 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


## Form input

## 输入表单

Text fields allow users to type text into your app so they can be
used to build forms, messaging apps, search experiences, and more.
Flutter provides two core text field widgets:
[`TextField`][] and [`TextFormField`][].

TextField 用于在应用程序中输入文本，这样就可以实现创建
表单、短消息应用、搜索框等等功能。Flutter 提供两个核心文本输入 widget：
[`TextField`][] 和 [`TextFormField`][].

### How do I use text field widgets?

### 如何使用文本输入 widget ？

In React Native, to enter text you use a `TextInput` component to show a text
input box and then use the callback to store the value in a variable.

在 RN 里，可以使用 `TextInput` 组件来输入文本，
它会显示一个输入框，然后通过回调函数来传递输入值。

```js
// React Native
const [password, setPassword] = useState('')
...
<TextInput
  placeholder="Enter your Password"
  onChangeText={password => setPassword(password)}
/>
<Button title="Submit" onPress={this.validate} />
```

In Flutter, use the [`TextEditingController`][]
class to manage a `TextField` widget.
Whenever the text field is modified,
the controller notifies its listeners.

在 Flutter 中，使用 [`TextEditingController`][]
类来管理 `TextField` widget。
当用户修改文本的时候，controller 会通知监听器。

Listeners read the text and selection properties to
learn what the user typed into the field.
You can access the text in `TextField`
by the `text` property of the controller.

监听器读取文本和选项属性来获知用户所输入的内容。
你可以通过 `TextField` 中的 `text`
属性获得用户输入的文本数据。

<?code-excerpt "lib/examples.dart (text-editing-controller)"?>
```dart
final TextEditingController _controller = TextEditingController();

@override
Widget build(BuildContext context) {
  return Column(
    children: [
      TextField(
        controller: _controller,
        decoration: const InputDecoration(
          hintText: 'Type something',
          labelText: 'Text Field',
        ),
      ),
      ElevatedButton(
        child: const Text('Submit'),
        onPressed: () {
          showDialog(
            context: context,
            builder: (context) {
              return AlertDialog(
                title: const Text('Alert'),
                content: Text('You typed ${_controller.text}'),
              );
            },
          );
        },
      ),
    ],
  );
}
```

In this example, when a user clicks on the submit button an alert dialog
displays the current text entered in the text field.
This is achieved using an [`AlertDialog`][]
widget that displays the alert message, and the text from
the `TextField` is accessed by the `text` property of the
[`TextEditingController`][].

在这个例子中，当用户点击提交按钮的时候，会弹出窗口显示当前输入的文本内容。
可以使用 [`alertDialog`][] widget 显示提示信息，
`TextField` 的文本通过 `text` 属性来获得，
该属性属于 [`TextEditingController`][]。

### How do I use Form widgets?

### 如何使用 Form widget 呢？

In Flutter, use the [`Form`][] widget where
[`TextFormField`][] widgets along with the submit
button are passed as children.
The `TextFormField` widget has a parameter called
[`onSaved`][] that takes a callback and executes
when the form is saved. A `FormState`
object is used to save, reset, or validate
each `FormField` that is a descendant of this `Form`.
To obtain the `FormState`, you can use `Form.of()`
with a context whose ancestor is the `Form`,
or pass a `GlobalKey` to the `Form` constructor and call
`GlobalKey.currentState()`.

在 Flutter 中，当需要使用带有提交按钮和 [`TextFormField`][]
组件的复合 widget 时，就会用到 [`Form`][]。
`TextFormField` 内含一个 [`onSaved`][] 参数，
它可以设置一个回调函数，当表单存储的时候会回调该函数。
`FormState` 用于存储、重置或者验证 `Form` 内含的每个 `FormField`。
你可以通过将当前表单的 context 属性赋值给 `Form.of` 来获得 `FormState`。
或者在表单的构造函数里使用 `GlobalKey`，
然后调用 `GlobalKey.currentState` 来获得 `FormState`。

<?code-excerpt "lib/examples.dart (form-state)"?>
```dart
@override
Widget build(BuildContext context) {
  return Form(
    key: formKey,
    child: Column(
      children: <Widget>[
        TextFormField(
          validator: (value) {
            if (value != null && value.contains('@')) {
              return null;
            }
            return 'Not a valid email.';
          },
          onSaved: (val) {
            _email = val;
          },
          decoration: const InputDecoration(
            hintText: 'Enter your email',
            labelText: 'Email',
          ),
        ),
        ElevatedButton(onPressed: _submit, child: const Text('Login')),
      ],
    ),
  );
}
```

The following example shows how `Form.save()` and `formKey`
(which is a `GlobalKey`), are used to save the form on submit.

下面的示例代码展示了 `Form.save()` 和 `formKey`
（使用 `GlobalKey`）如何被用于表单提交的。

<?code-excerpt "lib/examples.dart (form-submit)"?>
```dart
void _submit() {
  final form = formKey.currentState;
  if (form != null && form.validate()) {
    form.save();
    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: const Text('Alert'),
          content: Text('Email: $_email, password: $_password'),
        );
      },
    );
  }
}
```

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/input-fields.webp' alt='Input on Android' title='Input 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/input-fields.webp' alt='Input on iOS' title='Input 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


## Platform-specific code

## 平台相关代码

When building a cross-platform app, you want to re-use as much code as
possible across platforms. However, scenarios might arise where it
makes sense for the code to be different depending on the OS.
This requires a separate implementation by declaring a specific platform.

当构建跨平台应用程序的时候，你会尽量多地复用代码。
然而，根据不同的应用场景，代码会根据平台的不同有所变化。
这就需要提前声明具体的平台来进行独立的实现。

In React Native, the following implementation would be used:

在 RN 中，下面的实现代码会被用到：

```js
// React Native
if (Platform.OS === 'ios') {
  return 'iOS';
} else if (Platform.OS === 'android') {
  return 'android';
} else {
  return 'not recognised';
}
```

In Flutter, use the following implementation:

而在 Flutter 中，则是下面这样的实现：

<?code-excerpt "lib/examples.dart (platform)"?>
```dart
final platform = Theme.of(context).platform;
if (platform == TargetPlatform.iOS) {
  return 'iOS';
}
if (platform == TargetPlatform.android) {
  return 'android';
}
if (platform == TargetPlatform.fuchsia) {
  return 'fuchsia';
}
return 'not recognized ';
```

## Debugging

## 调试

### What tools can I use to debug my app in Flutter?

### 应该使用什么工具调试我的 Flutter 应用？

Use the [DevTools][] suite for debugging Flutter or Dart apps.

请使用 [DevTools][] 调试你的 Flutter 和 Dart 应用。

DevTools includes support for profiling, examining the heap,
inspecting the widget tree, logging diagnostics, debugging,
observing executed lines of code, debugging memory leaks and memory
fragmentation. For more information, check out the
[DevTools][] documentation.

开发者工具包含了 profiling 构建、检查堆栈、
检视 widget 树、诊断信息记录、调试、
执行代码行观察、调试内存泄漏和内存碎片等。
有关更多信息，请参阅 [DevTools][] 文档。

If you're using an IDE,
you can debug your application using the IDE's debugger.

如果你在用 IDE 进行编辑，你可以使用 IDE 的调试器调试你的应用。

### How do I perform a hot reload?

### 如何进行热重载？

Flutter's Stateful Hot Reload feature helps you quickly and easily experiment,
build UIs, add features, and fix bugs. Instead of recompiling your app
every time you make a change, you can hot reload your app instantly.
The app is updated to reflect your change,
and the current state of the app is preserved.

Flutter 的热重载特性可以帮助你快速便捷地实验、构建 UI 和各种特性以及修复 bug。
每次修改代码以后，你只需直接热重载你的应用程序即可，而无需重新进行编译。
应用程序会根据你的修改进行相应的更新，而程序原有的状态则会被保留。

First, from your preferred IDE,
enable autosave and hot reloads on save.

    **VS Code**

    Add the following to your `.vscode/settings.json` file:

    ```json
    "files.autoSave": "afterDelay",
    "dart.flutterHotReloadOnSave": "all",
    ```
    **Android Studio and IntelliJ**

    * Open `Settings > Tools > Actions on Save` and select
     `Configure autosave options`.
        - Check the option to `Save files if the IDE is idle for X seconds`.
        - **Recommended:** Set a small delay duration. For example, 2 seconds.

    * Open `Settings > Languages & Frameworks > Flutter`.
        - Check the option to `Perform hot reload on save`.


In React Native,
the shortcut is ⌘R for the iOS Simulator and tapping R twice on
Android emulators.

在 RN 中，iOS 模拟器对应的快捷键是 ⌘R，
对应 Android 模拟器的快捷键是点击两次 R。

In Flutter, if you are using IntelliJ IDE or Android Studio,
you can select Save All (⌘s/ctrl-s), or you can click the
Hot Reload button on the toolbar. If you
are running the app at the command line using `flutter run`,
type `r` in the Terminal window.
You can also perform a full restart by typing `R` in the
Terminal window.

在 Flutter 中，如果你使用的是 IntelliJ 或者 Android Studio，
可以使用 Save All (⌘s/ctrl-s)，或者可以点击工具栏上的 Hot Reload 按钮。
如果你是在命令行里使用 `flutter run` 命令运行的程序，在窗口里输入 `r` 即可。
也可以输入 `R` 进行彻底的重启。

### How do I access the in-app developer menu?

### 如何打开程序里的开发者菜单？

In React Native, the developer menu can be accessed by shaking your device: ⌘D
for the iOS Simulator or ⌘M for Android emulator.

在 RN 中，开发者菜单可以通过摇动设备打开：
对于 iOS 模拟器的快捷键是 ⌘D 而 Android 模拟器的快捷键是 ⌘M。

In Flutter, if you are using an IDE, you can use the IDE tools. If you start
your application using `flutter run` you can also access the menu by typing `h`
in the terminal window, or type the following shortcuts:

在 Flutter 中，如果你使用 IDE，那么可以直接使用 IDE 工具。
如果你是通过命令行运行 `flutter run` 来启动应用程序的，
你可以在命令行窗口通过输入 `h` 来打开菜单，或者参考下面的快捷键说明：

| Action| Terminal Shortcut| Debug functions and properties|
| :------- | :------: | :------ |
| 功能| 命令行快捷键| 调试功能和属性|
| Widget hierarchy of the app| `w`| debugDumpApp()|
| 应用程序的 widget 层级| `w`| debugDumpApp()|
| Rendering tree of the app | `t`| debugDumpRenderTree()|
| 渲染程序的 widget 树 | `t`| debugDumpRenderTree()|
| Layers| `L`| debugDumpLayerTree()|
| 层| `L`| debugDumpLayerTree()|
| Accessibility | `S` (traversal order) or<br>`U` (inverse hit test order)|debugDumpSemantics()|
| 无障碍 | `S` (遍历顺序) 或者<br>`U` (反转点击测试顺序)|debugDumpSemantics()|
| To toggle the widget inspector | `i` | WidgetsApp. showWidgetInspectorOverride|
| 打开或者关闭 widget 窗口 | `i` | WidgetsApp. showWidgetInspectorOverride|
| To toggle the display of construction lines| `p` | debugPaintSizeEnabled|
| 显示或者隐藏框架线条| `p` | debugPaintSizeEnabled|
| To simulate different operating systems| `o` | defaultTargetPlatform|
| 模拟不同的操作系统| `o` | defaultTargetPlatform|
| To display the performance overlay | `P` | WidgetsApp. showPerformanceOverlay|
| 叠加显示性能参数| `P` | WidgetsApp. showPerformanceOverlay|
| To save a screenshot to flutter. png| `s` ||
| 将截屏保存为 flutter.png| `s` ||
| To quit| `q` ||
| 退出| `q` ||

{:.table .table-striped}

## Animation

## 动画

Well-designed animation makes a UI feel intuitive,
contributes to the look and feel of a polished app,
and improves the user experience.
Flutter's animation support makes it easy
to implement simple and complex animations.
The Flutter SDK includes many Material Design widgets
that include standard motion effects,
and you can easily customize these effects
to personalize your app.

精美的动画效果会使得 UI 更加直观，可以提升整体视觉效果，
使应用显得更加精致，从而提升用户体验。
Flutter 的动画框架使得开发者能够更方便地实现简单和复杂的动画。
Flutter SDK 含有很多 Material Design widget。
其中已经包括了标准的动画效果，你可以很方便地自定义这些效果。

In React Native, Animated APIs are used to create animations.

在 RN 中，动画 API 用于创建动画。

In Flutter, use the [`Animation`][]
class and the [`AnimationController`][] class.
`Animation` is an abstract class that understands its
current value and its state (completed or dismissed).
The `AnimationController` class lets you
play an animation forward or in reverse,
or stop animation and set the animation
to a specific value to customize the motion.

在 Flutter 中，使用 [`Animation`][] 类和
[`AnimationController`][] 类实现动画。
`Animation` 是抽象类，内含其当前的值和它的状态（已完成或者已取消）。
`AnimationController` 类可以正向或者反向播放动画或者
停止动画以及为动画设置特定值来自定义动画。

### How do I add a simple fade-in animation?

### 如何添加一个简单的淡入动画效果？

In the React Native example below, an animated component,
`FadeInView` is created using the Animated API.
The initial opacity state, final state, and the
duration over which the transition occurs are defined.
The animation component is added inside the `Animated` component,
the opacity state `fadeAnim` is mapped
to the opacity of the `Text` component that we want to animate,
and then, `start()` is called to start the animation.

在下面的 React Native 示例中，有一个动画组件，也就是 `FadeInView`，
它是使用 Animated API 创建的。定义了初始的不透明状态，
最终状态和动画切换之间的时间间隔。在 `Animated` 中添加了动画组件，
不透明状态 `fadeAnim` 映射到我们想要添加动画效果的文本组件上，
然后在开始动画的时候调用 `start()`。

```js
// React Native
const FadeInView = ({ style, children }) => {
  const fadeAnim = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.timing(fadeAnim, {
      toValue: 1,
      duration: 10000
    }).start();
  }, []);

  return (
    <Animated.View style={{ ...style, opacity: fadeAnim }}>
      {children}
    </Animated.View>
  );
};
    ...
<FadeInView>
  <Text> Fading in </Text>
</FadeInView>
    ...
```

To create the same animation in Flutter, create an
[`AnimationController`][] object named `controller`
and specify the duration. By default, an `AnimationController`
linearly produces values that range from 0.0 to 1.0,
during a given duration. The animation controller generates a new value
whenever the device running your app is ready to display a new frame.
Typically, this rate is around 60 values per second.

要在 Flutter 中实现相同的动画效果，
创建一个 [`AnimationController`][] 对象，
叫它 `controller`，并且指定时间间隔。
在默认配置下，`AnimationController`
会在给定时间间隔线性地生成从 0.0 到 1.0 的数值。
当你的程序可以显示新一帧画面的时候，`AnimationController` 会生成一个新的值。
通常这个频率为每秒 60 次。

When defining an `AnimationController`,
you must pass in a `vsync` object.
The presence of `vsync` prevents offscreen
animations from consuming unnecessary resources.
You can use your stateful object as the `vsync` by adding
`TickerProviderStateMixin` to the class definition.
An `AnimationController` needs a TickerProvider,
which is configured using the `vsync` argument on the constructor.

当定义 `AnimationController` 的时候，你必须传入一个 `vsync` 对象。
`vsync` 会防止屏幕显示区域之外的动画消耗不必要的资源。
你可以通过添加 `TickerProviderStateMixin` 到类定义中来使用有状态的对象。
`AnimationController` 需要传入一个 TickerProvider，
它是通过构造函数里的 `vsync` 参数进行配置的。

A [`Tween`][] describes the interpolation between a
beginning and ending value or the mapping from an input
range to an output range. To use a `Tween` object
with an animation, call the `Tween` object's `animate()`
method and pass it the `Animation` object that you want to modify.

[`Tween`][] 定义了起始和结束值之间或者输入段到输出段之间的过渡。
如果要在动画中使用 `Tween` 对象，调用 `Tween` 对象的 `animate` 方法，
然后把它赋给你要修改的 `Animation` 对象。

For this example, a [`FadeTransition`][]
widget is used and the `opacity` property is
mapped to the `animation` object.

在这个例子中，用到了 [`FadeTransition`][] widget，
它的 `opacity` 属性映射到了 `animation` 对象上。

To start the animation, use `controller.forward()`.
Other operations can also be performed using the
controller such as `fling()` or `repeat()`.
For this example, the [`FlutterLogo`][]
widget is used inside the `FadeTransition` widget.

要开始动画，使用 `controller.forward()`。
其它的操作也可以使用控制器里的方法，
比如 `fling()` 或者 `repeat()`。
这个例子里，[`FlutterLogo`][] widget 
被用于 `FadeTransition` widget 中。

<?code-excerpt "lib/animation.dart"?>
```dart
import 'package:flutter/material.dart';

void main() {
  runApp(const Center(child: LogoFade()));
}

class LogoFade extends StatefulWidget {
  const LogoFade({super.key});

  @override
  State<LogoFade> createState() => _LogoFadeState();
}

class _LogoFadeState extends State<LogoFade>
    with SingleTickerProviderStateMixin {
  late Animation<double> animation;
  late AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      duration: const Duration(milliseconds: 3000),
      vsync: this,
    );
    final CurvedAnimation curve = CurvedAnimation(
      parent: controller,
      curve: Curves.easeIn,
    );
    animation = Tween(begin: 0.0, end: 1.0).animate(curve);
    controller.forward();
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: animation,
      child: const SizedBox(height: 300, width: 300, child: FlutterLogo()),
    );
  }
}
```

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/flutter-fade.webp' alt='Flutter fade on Android' title='Flutter fade 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/flutter-fade.webp' alt='Flutter fade on iOS' title='Flutter fade 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


### How do I add swipe animation to cards?

### 如何为卡片添加滑动动画呢？

In React Native, either the `PanResponder` or
third-party libraries are used for swipe animation.

在 RN 中，无论  `PanResponder` 或者第三方库都可被用于滑动动画。

In Flutter, to add a swipe animation, use the
[`Dismissible`][] widget and nest the child widgets.

在 Flutter 中，要添加滑动动画，
使用 [`Dismissible`][] widget 封装其它子 widget 即可。

<?code-excerpt "lib/examples.dart (dismissible)"?>
```dart
return Dismissible(
  key: Key(widget.key.toString()),
  onDismissed: (dismissDirection) {
    cards.removeLast();
  },
  child: Container(
    //...
  ),
);
```

<figure>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/android/react-native/card-swipe.webp' alt='Card swipe on Android' title='Card swipe 在 Android 上' class='border'>
    <figcaption class="figure-caption">Android</figcaption>
  </div>
  <div class="site-figure-container">
    <img src='/assets/images/docs/get-started/ios/react-native/card-swipe.webp' alt='Card swipe on iOS' title='Card swipe 在 iOS 上' class='border'>
    <figcaption class="figure-caption">iOS</figcaption>
  </div>
</figure>


## React Native and Flutter widget equivalent components

## React Native 和 Flutter widget 对等的组件

The following table lists commonly-used React Native
components mapped to the corresponding Flutter widget
and common widget properties.

下面的表格列举了通用的 React Native 组件与对应的
Flutter widget 和通用的 widget 属性。

| <t>React Native Component</t><t>React Native 组件</t> | Flutter Widget      | <t>Description</t><t>描述</t> |
| ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| [`Button`](https://reactnative.dev/docs/button)                        | [`ElevatedButton`][]                           | A basic raised button.                                                                              |
| [`Button`](https://reactnative.dev/docs/button)                        | [`ElevatedButton`][]                           | 基础的凸起按钮                                                                                       |
|                                                                                           |  onPressed [required]                                                                                        | The callback when the button is tapped or otherwise activated.                                                          |
|                                                                                           |  onPressed [必选]                                                                                            | 该回调函数在当按钮被点击的时候被触发。                                                                                     |
|                                                                                           | Child                                                                              | The button's label.                                                                                                      |
|                                                                                           | Child                                                                              | 按钮的标签                                                                                                                |
|                                                                                           |                                                                                                            |                                                                                                                                        |
| [`Button`](https://reactnative.dev/docs/button)                        | [`TextButton`][]                               | A basic flat button.                                                                                                         |
| [`Button`](https://reactnative.dev/docs/button)                        | [`TextButton`][]                               | 基础的扁平化按钮.                                                                                                             |
|                                                                                           |  onPressed [required]                                                                                        | The callback when the button is tapped or otherwise activated.                                                            |
|                                                                                           |  onPressed [必选]                                                                                            | 当按钮被点击的时候触发该回调函数。                                                                                           |
|                                                                                           | Child                                                                              | The button's label.                                                                                                      |
|                                                                                           | Child                                                                              | 按钮的标签                                                                                                                |
|                                                                                           |                                                                                                            |                                                                                                                                        |
| [`ScrollView`](https://reactnative.dev/docs/scrollview)                | [`ListView`][]                                    | A scrollable list of widgets arranged linearly.|
| [`ScrollView`](https://reactnative.dev/docs/scrollview)                | [`ListView`][]                                    | 一个可滑动的纵向排列的 widget 列表。             |
||        children                                                                              | 	( <Widget\> [ ])  List of child widgets to display.
||        children                                                                              | 	( <Widget\> [ ])  要显示的子 widget 列表
||controller |[ [`ScrollController`][] ] An object that can be used to control a scrollable widget.
||controller |[ [`ScrollController`][] ] 可用于控制滑动 widget 的对象
||itemExtent|[ double ] If non-null, forces the children to have the given extent in the scroll direction.
||itemExtent|[ double ] 如果非空，那么强制所有子 widget 在滑动方向上增加给定的距离
||scroll Direction|[ [`Axis`][] ] The axis along which the scroll view scrolls.
||scroll Direction|[ [`Axis`][] ] 滑动页面的滑动轴
||                                                                                                            |                                                                                                                                        |
| [`FlatList`](https://reactnative.dev/docs/flatlist)                    | [`ListView.builder`][]               | The constructor for a linear array of widgets that are created on demand.
| [`FlatList`](https://reactnative.dev/docs/flatlist)                    | [`ListView.builder`][]               | 根据需要创建的一组 widget 的构造函数。
||itemBuilder [required] |[[`IndexedWidgetBuilder`][]] helps in building the children on demand. This callback is called only with indices greater than or equal to zero and less than the itemCount.
||itemBuilder [required] |[[`IndexedWidgetBuilder`][]] 根据需要创建子 widget。当元素序号大于等于零并且小于队列元素总数时，该回调函数会被调用。
||itemCount |[ int ] improves the ability of the `ListView` to estimate the maximum scroll extent.
||itemCount |[ int ] 优化了 ListView 对于最大滑动范围的预估能力。
|                                                                                           |                                                                                                            |                                                                                                                                        |
| [`Image`](https://reactnative.dev/docs/image)                         | [`Image`][]                                           | A widget that displays an image.                                                                                                       |
| [`Image`](https://reactnative.dev/docs/image)                         | [`Image`][]                                           | 显示图片的 widget。                                                                                                                     |
|                                                                                           |  image [required]                                                                                          | The image to display.                                                                                                                  |
|                                                                                           |  image [必选]                                                                                              | 要显示的图片                                                                                                                            |
|                                                                                           | Image. asset                                                                                                | Several constructors are provided for the various ways that an image can be specified.                                                 |
|                                                                                           | Image. asset                                                                                                | 有多个构造函数可以用于指定图片。                                                                                                          |
|                                                                                           | width, height, color, alignment                                                                            | The style and layout for the image.                                                                                                         |
|                                                                                           | width, height, color, alignment                                                                            | 图片的风格和布局。                                                                                                                           |
|                                                                                           | fit                                                                                                        | Inscribing the image into the space allocated during layout.                                                                           |
|                                                                                           | fit                                                                                                        | 将图片内嵌到布局对应的空间里。                                                                                                            |
|                                                                                           |                                                                                                            |                                                                                                                                        |
| [`Modal`](https://reactnative.dev/docs/modal)                          | [`ModalRoute`][]                                | A route that blocks interaction with previous routes.                                                                                  |
| [`Modal`](https://reactnative.dev/docs/modal)                          | [`ModalRoute`][]                                | 避免和之前路径交叉的路径。                                                                                                               |
|                                                                                           | animation                                                                                                  | The animation that drives the route's transition and the previous route's forward transition.                                          |
|                                                                                           | animation                                                                                                  | 路径切换的动画和之前路径向前切换的动画。                                                                                                  |
|                                                                                           |                                                                                                            |                                                                                                                                        |
|  [`ActivityIndicator`](https://reactnative.dev/docs/activityindicator) | [`CircularProgressIndicator`][] | A widget that shows progress along a circle.                                                                                           |
|  [`ActivityIndicator`](https://reactnative.dev/docs/activityindicator) | [`CircularProgressIndicator`][] | 一个圆形进度条 widget。                                                                                                                 |
|                                                                                           | strokeWidth                                                                                                | The width of the line used to draw the circle.                                                                                         |
|                                                                                           | strokeWidth                                                                                                | 圆形线条的宽度。                                                                                                                        |
|                                                                                           | backgroundColor                                                                                            | The progress indicator's background color. The current theme's `ThemeData.backgroundColor` by default.                                   |
|                                                                                           | backgroundColor                                                                                            | 指示进度的背景色。默认是当前主题的 `ThemeData.backgroundColor`。                                                                            |
|                                                                                           |                                                                                                            |                                                                                                                                        |
|  [`ActivityIndicator`](https://reactnative.dev/docs/activityindicator) | [`LinearProgressIndicator`][]     | A widget that shows progress along a line.                                                                                           |
|  [`ActivityIndicator`](https://reactnative.dev/docs/activityindicator) | [`LinearProgressIndicator`][]     | 一个水平条形的进度条。                                                                                                                 |
|                                                                                           | value                                                                                                      | The value of this progress indicator.                                                                                                   |
|                                                                                           | value                                                                                                      | 进度条的进度值。                                                                                                                         |
|                                                                                           |                                                                                                            |                                                                                                                                        |
| [`RefreshControl`](https://reactnative.dev/docs/refreshcontrol)        | [`RefreshIndicator`][]                   | A widget that supports the Material "swipe to refresh" idiom.                                                                          |
| [`RefreshControl`](https://reactnative.dev/docs/refreshcontrol)        | [`RefreshIndicator`][]                   | 支持 Material 中滑动刷新的 widget                                                                                                       |
|                                                                                           | color                                                                                                      | The progress indicator's foreground color.                                                                                             |
|                                                                                           | color                                                                                                      | 进度指示的前景色。                                                                                                                      |
|                                                                                           | onRefresh                                                                                                  | A function that's called when a user drags the refresh indicator far enough to demonstrate that they want the app to refresh.  |
|                                                                                           | onRefresh                                                                                                  | 	当用户拖拽刷新指示器想要刷新的时候会调用该函数。                                                                                  |
|                                                                                           |                                                                                                            |                                                                                                                                        |
| [`View`](https://reactnative.dev/docs/view)                            | [`Container`][]                                  | A widget that surrounds a child widget.                                                                                                                |
| [`View`](https://reactnative.dev/docs/view)                            | [`Container`][]                                  | 封装子 widget 的 widget。                                                                                                                              |
|                                                                                           |                                                                                                            |                                                                                                                                        |
| [`View`](https://reactnative.dev/docs/view)                            | [`Column`][]                                        | A widget that displays its children in a vertical array.                                                                                              |
| [`View`](https://reactnative.dev/docs/view)                            | [`Column`][]                                        | 将子 widget 纵向排列的 widget。                                                                                                                        |
|                                                                                           |                                                                                                            |                                                                                                                                        |
| [`View`](https://reactnative.dev/docs/view)                            | [`Row`][]                                              | A widget that displays its children in a horizontal array.                                                                                            |
| [`View`](https://reactnative.dev/docs/view)                            | [`Row`][]                                              | 将子 widget 横向排列的 widget。                                                                                                                        |
|                                                                                           |                                                                                                            |                                                                                                                                        |
| [`View`](https://reactnative.dev/docs/view)                            | [`Center`][]                                        | A widget that centers its child within itself.                                                                                                       |
| [`View`](https://reactnative.dev/docs/view)                            | [`Center`][]                                        | 将子 widget 放置于中央的 widget。                                                                                                                     |                                                                                                            |                                                                                                                                        |
|                                                                                           |                                                                                                            |                                                                                                                                        |
| [`View`](https://reactnative.dev/docs/view)                            | [`Padding`][]                                      | A widget that insets its child by the given padding.                                                                                                 |
| [`View`](https://reactnative.dev/docs/view)                            | [`Padding`][]                                      | 将子 widget 按照给定的间隔进行排列的 widget。                                                                                                           |
|                                                                                           | padding [required]                                                                                         | [ EdgeInsets ] The amount of space to inset the child.
|                                                                                           | padding [必选]                                                                                             | [ EdgeInsets ] 子 widget 间隔。
|||
| [`TouchableOpacity`](https://reactnative.dev/docs/touchableopacity)    | [`GestureDetector`][]                      | A widget that detects gestures.                                                                                                                       |
| [`TouchableOpacity`](https://reactnative.dev/docs/touchableopacity)    | [`GestureDetector`][]                      | 检测手势的 widget。                                                                                                                                    |
|                                                                                           | onTap                                                                                                      | A callback when a tap occurs.                                                                                                               |
|                                                                                           | onTap                                                                                                      | 当点击的时候会调用。                                                                                                                          |
|                                                                                           | onDoubleTap                                                                                                | A callback when a tap occurs at the same location twice in quick succession.
|                                                                                           | onDoubleTap                                                                                                | 当两次点击的时候会调用。
|||
| [`TextInput`](https://reactnative.dev/docs/textinput)                | [`TextInput`][]                                   | The interface to the system's text input control.                                                                                           |
| [`TextInput`](https://reactnative.dev/docs/textinput)                | [`TextInput`][]                                   | 调用系统文本输入的接口。                                                                                                                      |
|                                                                                           | controller                                                                                                 | [ [`TextEditingController`][] ] used to access and modify text.
|                                                                                           | controller                                                                                                 | [ [`TextEditingController`][] ] 用于获取或者修改文本。
|||
| [`Text`](https://reactnative.dev/docs/text)                          | [`Text`][]                                            | The Text widget that displays a string of text with a single style.                                                                                                                                                                           |
| [`Text`](https://reactnative.dev/docs/text)                          | [`Text`][]                                            | 以单一的样式显示文本的文本 widget。                                                                                                                                                                                                             |
|                                                                                         | data                                                                                                      | [ String ] The text to display.                                                                                                                                                                              |
|                                                                                         | data                                                                                                      | [ String ] 要显示的文本。                                                                                                                                                                         |
|                                                                                         | textDirection                                                                                             | [ [`TextAlign`][] ] The direction in which the text flows.                                                                                                                                      |
|                                                                                         | textDirection                                                                                             | [ [`TextAlign`][] ] 文本的方向。                                                                                                                                                                 |
|                                                                                         |                                                                                                           |                                                                                                                                                                                                              |
| [`Switch`](https://reactnative.dev/docs/switch)                      | [`Switch`][]                                      | A material design switch.                                                                                                                                                                                    |
| [`Switch`](https://reactnative.dev/docs/switch)                      | [`Switch`][]                                      | Material Design 样式的开关。                                                                                                                                                                                  |
|                                                                                         | value [required]                                                                                          | [ boolean ] Whether this switch is on or off.                                                                                                                                                                 |
|                                                                                         | value [必选]                                                                                              | [ boolean ] 开关的开启或者闭合状态。                                                                                                                                                                            |
|                                                                                         | onChanged [required]                                                                                      | [ callback ] Called when the user toggles the switch on or off.                                                                                                                                               |
|                                                                                         | onChanged [必选]                                                                                          | [ callback ] 当用户点击开关的时候调用。                                                                                                                                                                          |

{:.table .table-striped}


[`AboutDialog`]: https://api.flutter-io.cn/flutter/material/AboutDialog-class.html
[Adding Assets and Images in Flutter]: /ui/assets/assets-and-images
[`AlertDialog`]: https://api.flutter-io.cn/flutter/material/AlertDialog-class.html
[`Align`]: https://api.flutter-io.cn/flutter/widgets/Align-class.html
[`Animation`]: https://api.flutter-io.cn/flutter/animation/Animation-class.html
[`AnimationController`]: https://api.flutter-io.cn/flutter/animation/AnimationController-class.html
[async and await]: https://dart.cn/language/async
[`Axis`]: https://api.flutter-io.cn/flutter/painting/Axis.html
[`BuildContext`]: https://api.flutter-io.cn/flutter/widgets/BuildContext-class.html
[`Center`]: https://api.flutter-io.cn/flutter/widgets/Center-class.html
[color palette]: https://m2.material.io/design/color/the-color-system.html#color-theme-creation
[colors]: https://api.flutter-io.cn/flutter/material/Colors-class.html
[`Colors`]: https://api.flutter-io.cn/flutter/material/Colors-class.html
[`Column`]: https://api.flutter-io.cn/flutter/widgets/Column-class.html
[`Container`]: https://api.flutter-io.cn/flutter/widgets/Container-class.html
[`Checkbox`]: https://api.flutter-io.cn/flutter/material/Checkbox-class.html
[`CircleAvatar`]: https://api.flutter-io.cn/flutter/material/CircleAvatar-class.html
[`CircularProgressIndicator`]: https://api.flutter-io.cn/flutter/material/CircularProgressIndicator-class.html
[Cupertino (iOS-style)]: /ui/widgets/cupertino
[`CustomPaint`]: https://api.flutter-io.cn/flutter/widgets/CustomPaint-class.html
[`CustomPainter`]: https://api.flutter-io.cn/flutter/rendering/CustomPainter-class.html
[Dart]: https://dart.cn/dart-2
[Dart's Type System]: https://dart.cn/guides/language/sound-dart
[Sound Null Safety]: https://dart.cn/null-safety
[`dart:io`]: https://api.flutter-io.cn/flutter/dart-io/dart-io-library.html
[DartPadA]: https://dartpad.cn/?id=0df636e00f348bdec2bc1c8ebc7daeb1
[DartPadB]: https://dartpad.cn/?id=cf9e652f77636224d3e37d96dcf238e5
[DartPadC]: https://dartpad.cn/?id=3f4625c16e05eec396d6046883739612
[DartPadD]: https://dartpad.cn/?id=57ec21faa8b6fe2326ffd74e9781a2c7
[DartPadE]: https://dartpad.cn/?id=c85038ad677963cb6dc943eb1a0b72e6
[DartPadF]: https://dartpad.cn/?id=5454e8bfadf3000179d19b9bc6be9918
[Developing Packages & Plugins]: /packages-and-plugins/developing-packages
[DevTools]: /tools/devtools
[`Dismissible`]: https://api.flutter-io.cn/flutter/widgets/Dismissible-class.html
[`FadeTransition`]: https://api.flutter-io.cn/flutter/widgets/FadeTransition-class.html
[Flutter packages]: https://pub-web.flutter-io.cn/flutter/
[Flutter Architectural Overview]: /resources/architectural-overview
[Flutter Basic Widgets]: /ui/widgets/basics
[Flutter Technical Overview]: /resources/architectural-overview
[Flutter Widget Catalog]: /ui/widgets
[Flutter Widget Index]: /reference/widgets
[`FlutterLogo`]: https://api.flutter-io.cn/flutter/material/FlutterLogo-class.html
[`Form`]: https://api.flutter-io.cn/flutter/widgets/Form-class.html
[`TextButton`]: https://api.flutter-io.cn/flutter/material/TextButton-class.html
[functions]: https://dart.cn/language/functions
[`Future`]: https://dart.cn/tutorials/language/futures
[`GestureDetector`]: https://api.flutter-io.cn/flutter/widgets/GestureDetector-class.html
[Getting started]: /install
[`Image`]: https://api.flutter-io.cn/flutter/widgets/Image-class.html
[`IndexedWidgetBuilder`]: https://api.flutter-io.cn/flutter/widgets/IndexedWidgetBuilder.html
[`InheritedWidget`]: https://api.flutter-io.cn/flutter/widgets/InheritedWidget-class.html
[`InkWell`]: https://api.flutter-io.cn/flutter/material/InkWell-class.html
[Layout Widgets]: /ui/widgets/layout
[`LinearProgressIndicator`]: https://api.flutter-io.cn/flutter/material/LinearProgressIndicator-class.html
[`ListTile`]: https://api.flutter-io.cn/flutter/material/ListTile-class.html
[`ListView`]: https://api.flutter-io.cn/flutter/widgets/ListView-class.html
[`ListView.builder`]: https://api.flutter-io.cn/flutter/widgets/ListView/ListView.builder.html
[Material Design]: https://m3.material.io/styles
[Material icons]: https://api.flutter-io.cn/flutter/material/Icons-class.html
[`MaterialApp`]: https://api.flutter-io.cn/flutter/material/MaterialApp-class.html
[`MaterialPageRoute`]: https://api.flutter-io.cn/flutter/material/MaterialPageRoute-class.html
[`ModalRoute`]: https://api.flutter-io.cn/flutter/widgets/ModalRoute-class.html
[`Navigator`]: https://api.flutter-io.cn/flutter/widgets/Navigator-class.html
[`Navigator.of()`]: https://api.flutter-io.cn/flutter/widgets/Navigator/of.html
[`Navigator.pop`]: https://api.flutter-io.cn/flutter/widgets/Navigator/pop.html
[`Navigator.push`]: https://api.flutter-io.cn/flutter/widgets/Navigator/push.html
[`onSaved`]: https://api.flutter-io.cn/flutter/widgets/FormField/onSaved.html
[named parameters]: https://dart.cn/language/functions#named-parameters
[`Padding`]: https://api.flutter-io.cn/flutter/widgets/Padding-class.html
[`PanResponder`]: https://reactnative.dev/docs/panresponder
[pub.dev]: https://pub-web.flutter-io.cn
[`Radio`]: https://api.flutter-io.cn/flutter/material/Radio-class.html
[`ElevatedButton`]: https://api.flutter-io.cn/flutter/material/ElevatedButton-class.html
[`RefreshIndicator`]: https://api.flutter-io.cn/flutter/material/RefreshIndicator-class.html
[`Route`]: https://api.flutter-io.cn/flutter/widgets/Route-class.html
[`Row`]: https://api.flutter-io.cn/flutter/widgets/Row-class.html
[`Scaffold`]: https://api.flutter-io.cn/flutter/material/Scaffold-class.html
[`ScrollController`]: https://api.flutter-io.cn/flutter/widgets/ScrollController-class.html
[`shared_preferences`]: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences
[`SingleTickerProviderStateMixin`]: https://api.flutter-io.cn/flutter/widgets/SingleTickerProviderStateMixin-mixin.html
[`Slider`]: https://api.flutter-io.cn/flutter/material/Slider-class.html
[`Stack`]: https://api.flutter-io.cn/flutter/widgets/Stack-class.html
[State management]: /data-and-backend/state-mgmt
[`StatefulWidget`]: https://api.flutter-io.cn/flutter/widgets/StatefulWidget-class.html
[`StatelessWidget`]: https://api.flutter-io.cn/flutter/widgets/StatelessWidget-class.html
[`Switch`]: https://api.flutter-io.cn/flutter/material/Switch-class.html
[`Tab`]: https://api.flutter-io.cn/flutter/material/Tab-class.html
[`TabBar`]: https://api.flutter-io.cn/flutter/material/TabBar-class.html
[`TabBarView`]: https://api.flutter-io.cn/flutter/material/TabBarView-class.html
[`TabController`]: https://api.flutter-io.cn/flutter/material/TabController-class.html
[`Text`]: https://api.flutter-io.cn/flutter/widgets/Text-class.html
[`TextAlign`]: https://api.flutter-io.cn/flutter/dart-ui/TextAlign.html
[`TextEditingController`]: https://api.flutter-io.cn/flutter/widgets/TextEditingController-class.html
[`TextField`]: https://api.flutter-io.cn/flutter/material/TextField-class.html
[`TextFormField`]: https://api.flutter-io.cn/flutter/material/TextFormField-class.html
[`TextInput`]: https://api.flutter-io.cn/flutter/services/TextInput-class.html
[`TextStyle`]: https://api.flutter-io.cn/flutter/dart-ui/TextStyle-class.html
[`Theme`]: https://api.flutter-io.cn/flutter/material/Theme-class.html
[`ThemeData`]: https://api.flutter-io.cn/flutter/material/ThemeData-class.html
[`Ticker`]: https://api.flutter-io.cn/flutter/scheduler/Ticker-class.html
[`TickerProvider`]: https://api.flutter-io.cn/flutter/scheduler/TickerProvider-class.html
[`TickerProviderStateMixin`]: https://api.flutter-io.cn/flutter/widgets/TickerProviderStateMixin-mixin.html
[`Tween`]: https://api.flutter-io.cn/flutter/animation/Tween-class.html
[Using Packages]: /packages-and-plugins/using-packages
[variables]: https://dart.cn/language/variables
[`WidgetBuilder`]: https://api.flutter-io.cn/flutter/widgets/WidgetBuilder.html
[infinite_list]: https://github.com/flutter/samples/tree/main/infinite_list

