第一个应用
用 Android Studio 和 VS Code 创建的 Flutter 应用模板默认是一个简单的计数器示例。本节先仔细讲解一下这个计数器 Demo 的源码,让读者对 Flutter 应用程序结构有个基本了解,然后在随后的小节中将会基于此示例,一步一步添加一些新的功能来介绍 Flutter 应用的其他概念与技术。
# 创建 Flutter 应用模板
# 创建应用
- 使用 Android Studio 创建一个 Flutter 工程,过程略。创建好后,就会得到一个默认的计数器应用示例。
- 在这个示例中,主要 Dart 代码是在
lib/main.dart
文件中,下面是它的源码:
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
# 模板代码分析
# 导入包
import 'package:flutter/material.dart';
此行代码作用是导入了 Material UI 组件库。Material (opens new window) 是一种标准的移动端和 web 端的视觉设计语言, Flutter 默认提供了一套丰富的 Material 风格的 UI 组件。
# 应用入口
void main() => runApp(MyApp());
与 C/C++、Java 类似,Flutter 应用中
main
函数为应用程序的入口。main
函数中调用了runApp
方法,它的功能是启动 Flutter 应用。runApp
它接受一个Widget
参数,在本示例中它是一个MyApp
对象,MyApp()
是 Flutter 应用的根组件。读者现在只需知道 runApp 是 Flutter 应用的入口即可,关于 Flutter 应用的启动流程,我们会在本书后面原理篇中做详细介绍。
main
函数使用了 (=>
) 符号,这是 Dart 中单行函数或方法的简写。
# 应用结构
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
//应用名称
title: 'Flutter Demo',
theme: ThemeData(
//蓝色主题
primarySwatch: Colors.blue,
),
//应用首页路由
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
MyApp
类代表 Flutter 应用,它继承了StatelessWidget
类,这也就意味着应用本身也是一个 widget。- 在 Flutter 中,大多数东西都是 widget(后同 “组件” 或 “部件”),包括对齐(Align)、填充(Padding)、手势处理(GestureDetector)等,它们都是以 widget 的形式提供。
- Flutter 在构建页面时,会调用组件的
build
方法,widget 的主要工作是提供一个 build () 方法来描述如何构建 UI 界面(通常是通过组合、拼装其他基础 widget )。 MaterialApp
是 Material 库中提供的 Flutter APP 框架,通过它可以设置应用的名称、主题、语言、首页及路由列表等。MaterialApp
也是一个 widget。home
为 Flutter 应用的首页,它也是一个 widget
# 首页
# 初识 Widget
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
...
}
MyHomePage
是应用的首页,它继承自StatefulWidget
类,表示它是一个有状态的组件(Stateful widget)。- 有状态的组件(Stateful widget) 和无状态的组件(Stateless widget)有两点不同:
- Stateful widget 可以拥有状态,这些状态在 widget 生命周期中是可以变的,而 Stateless widget 是不可变的。
- Stateful widget 至少由两个类组成:
- 一个
StatefulWidget
类。 - 一个
State
类;StatefulWidget
类本身是不变的,但是State
类中持有的状态在 widget 生命周期中可能会发生变化。
- 一个
# State 类
笔记
类似于 React 的 Redux
# _MyHomePageState 类解析
组件的状态
由于需要维护一个点击次数计数器,所以定义一个 _counter
状态:
int _counter = 0; //用于记录按钮点击的总次数
设置状态的自增函数
void _incrementCounter() {
setState(() {
_counter++;
});
}
笔记
这里需要在 setState
函数中执行更新 _counter++
逻辑,是因为只有在调用 setState
方法才会触发 build
方法来根据新的状态重新构建界面(重新渲染)。
构建 UI 界面的 build
方法
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Scaffold
是 Material 库中提供的页面脚手架 (opens new window),它提供了默认的导航栏、标题和包含主屏幕 widget 树(后同 “组件树” 或 “部件树”)的body
属性,组件树可以很复杂。本书后面示例中,路由默认都是通过Scaffold
创建。body
的组件树中包含了一个Center
组件,Center
可以将其子组件树对齐到屏幕中心。此例中,Center
子组件是一个Column
组件,Column
的作用是将其所有子组件沿屏幕垂直方向依次排列; 此例中Column
子组件是两个Text
,第一个Text
显示固定文本 “You have pushed the button this many times:”,第二个Text
显示_counter
状态的数值。floatingActionButton
是页面右下角的带 “+” 的悬浮按钮,它的onPressed
属性接受一个回调函数,代表它被点击后的处理器,本例中直接将_incrementCounter
方法作为其处理函数。
现在,我们将整个计数器执行流程串起来:当右下角的 floatingActionButton
按钮被点击之后,会调用 _incrementCounter
方法。在 _incrementCounter
方法中,首先会自增 _counter
计数器(状态),然后 setState
会通知 Flutter 框架状态发生变化,接着,Flutter 框架会调用 build
方法以新的状态重新构建 UI,最终显示在设备屏幕上。