一、创建工程
环境安装配置好后,打开Android Studio开发工具,选择Flutter,确认Flutter SDK path,点击Next。
选择Projects,点击New Flutter Project,新建Flutter项目。
设置Project name、Project location、Android language、iOS language后点击Finish,生成项目工程。
- Project name:项目名称
- Project location :项目本地路径
- Android language:安卓开发语言
- iOS language:iOS开发语言
二、代码分析
2.1 runApp
runApp是Flutter内部提供的一个函数,当启动一个Flutter应用程序时就是从调用此函数开始,runApp的函数定义如下:
void runApp(Widget app) {
...
}
2.2 Widget
Widget我们一般翻译为组件,类似于移动端安卓、iOS开发中的控件。
Flutter中万物皆Widget,runApp函数需要传入一个Widget,我们可以根据Flutter提供的Material库,使用其中的很多内置Widget,后面我们会讲到的基础组件、容器组件、布局组件、滚动组件等等都是不同的Widget。
2.3 Material
Flutter 提供了一套丰富 的Material 组件,它可以帮助我们构建遵循 Material Design 设计规范的应用程序。Material 应用程序以MaterialApp (opens new window) 组件开始, 同时是否使用MaterialApp (opens new window)完全是可选的。要使用 Material 组件,需要先引入它:
import 'package:flutter/material.dart';
MyApp中build返回的是MaterialApp,整个应用采用MaterialApp风格,其中三个属性:
- title:应用程序的描述标题,可以不写;
- theme:用于配置应用的主题;
home:应用启动时显示的页面;
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
2.4 Cupertino
Flutter 也提供了一套丰富的 Cupertino 风格的组件,尽管目前还没有 Material 组件那么丰富,但是它仍在不断的完善中。
既然有Material风格的MaterialApp,也应该有Cupertino(iOS)风格的CupertinoApp,CupertinoApp的属性及用法和MaterialApp一样。三、StatelessWidget和StatefulWidget
3.1 创建Widget
StatelessWidget 和 StatefulWidget 是 flutter 的基础组件,日常开发中自定义 Widget 都是选择继承这两者之一。在实际使用中,Stateless 与 Stateful 的选择需要取决于界面是否需要更新。
- StatelessWidget:无状态的,展示信息,面向那些始终不变的 UI 控件;
- StatefulWidget:有状态的,可以通过改变状态使得 UI 发生变化,可 以包含用户交互。
3.2 StatelessWidget
StatelessWidget 用于不需要维护状态的场景,它通常在 build 方法中通过嵌套其它 Widget 来构建 UI,在构建过程中会递归的构建其嵌套的 Widget
BuildContext 表示构建 widget 的上下文,它是操作 widget 在树中位 置的一个句柄,它包含了一些查找、遍历当前 Widget 树的一些方法。 每一个 widget 都有一个自己的 context 对象。
Flutter示例程序代码: ``` class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key);
@override Widget build(BuildContext context) { return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
3.3 StatefulWidget
StatefulWidget是动态的,当创建StatefulWidget时,Flutter将StatefulWidget设计成了两个类:
- 一个类继承自StatefulWidget,作为Widget树的一部分;
- 一个类继承自State,用于记录StatefulWidget会变化的状态,并且根据状态的变化,构建出新的Widget;可以手动调用其 setState()方法通知 Flutter framework 状态发生改变,Flutter framework 在收到消息后,会重新调用其 build 方法重新构建 widget 树,从而达到更新 UI 的目的。
Flutter示例程序缩减代码:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {...}
@override
Widget build(BuildContext context) {
return Scaffold(...)
}
}
四、生命周期
什么是生命周期,在Flutter中是一个组件的创建到销毁的的过程
StatelessWidget 组件生命周期函数 : 只有 createElement()、build() 两个函数 ;
abstract class StatelessWidget extends Widget {
const StatelessWidget({ Key? key }) : super(key: key);
@override
StatelessElement createElement() => StatelessElement(this);
@protected
Widget build(BuildContext context);
}
StatefulWidget需要通过State来管理数据,监控状态的改变决定是否重新build整个Widget;我们主要讨论StatefulWidget的生命周期,还是以Flutter示例程序为例:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
@override
void initState() {
super.initState();
debugPrint("initState");
}
void _incrementCounter() {...}
@override
Widget build(BuildContext context) {
debugPrint("build");
return Scaffold(...);
}
@override
void didUpdateWidget(covariant MyHomePage oldWidget) {
super.didUpdateWidget(oldWidget);
debugPrint("didUpdateWidget");
}
@override
void deactivate() {
super.deactivate();
debugPrint("deactivate");
}
@override
void dispose() {
super.dispose();
debugPrint("dispose");
}
@override
void reassemble() {
super.reassemble();
debugPrint("reassemble");
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
debugPrint("didChangeDependencies");
}
}
运行应用控制台日志输出,在StatefulWidget插入到 widget 树时首先initState方法会被调用。
flutter: initState
flutter: didChangeDependencies
flutter: build
点击⚡️按钮热重载,控制台输出日志如下,initState 和didChangeDependencies都没有被调用
flutter: reassemble
flutter: build
接下来,我们在 widget 树中移除MyHomePage,将 MyApp 的 build方法改为:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const Text("Flutter"),
);
}
}
点击⚡️按钮热重载,控制台输出日志如下,在MyHomePage从 widget 树中移除时,deactive和dispose会依次被调用。
flutter: reassemble
flutter: deactivate
flutter: dispose
Flutter回调函数:
initState:当 widget 第一次插入到 widget 树时会被调用,对于每一个State对象,Flutter 框架只会调用一次该回调,所以通常在该回调中做一些初始化、注册事件监听的操作等。
didChangeDependencies():组件创建执行initState() 后被调用,同时当State对象的依赖发生变化时会被调用,如InheritedWidget(暂不涉及)。
build():主要是用于构建 widget 子树,在initState()、setState()、didChangeDependencies()之后被调用。
reassemble():此回调是专门为了开发调试而提供的,在热重载(hot reload)时会被调用,此回调在Release模式下永远不会被调用。
didUpdateWidget ():在 widget 重新构建时,Flutter 框架会调用widget.canUpdate来检测 widget 树中同一位置的新旧节点,然后决定是否需要更新,如果widget.canUpdate返回true则会调用此回调。
deactivate():当 State 对象从树中被移除时,会调用此回调。
dispose():当 State 对象从树中被永久移除时调用;通常在此回调中释放资源。
StatefulWidget 生命周期如图: