一、创建工程
环境安装配置好后,打开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);@overrideWidget 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;@overrideState<MyHomePage> createState() => _MyHomePageState();}class _MyHomePageState extends State<MyHomePage> {int _counter = 0;void _incrementCounter() {...}@overrideWidget build(BuildContext context) {return Scaffold(...)}}
四、生命周期
什么是生命周期,在Flutter中是一个组件的创建到销毁的的过程
StatelessWidget 组件生命周期函数 : 只有 createElement()、build() 两个函数 ;
abstract class StatelessWidget extends Widget {const StatelessWidget({ Key? key }) : super(key: key);@overrideStatelessElement createElement() => StatelessElement(this);@protectedWidget 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;@overrideState<MyHomePage> createState() => _MyHomePageState();}class _MyHomePageState extends State<MyHomePage> {int _counter = 0;@overridevoid initState() {super.initState();debugPrint("initState");}void _incrementCounter() {...}@overrideWidget build(BuildContext context) {debugPrint("build");return Scaffold(...);}@overridevoid didUpdateWidget(covariant MyHomePage oldWidget) {super.didUpdateWidget(oldWidget);debugPrint("didUpdateWidget");}@overridevoid deactivate() {super.deactivate();debugPrint("deactivate");}@overridevoid dispose() {super.dispose();debugPrint("dispose");}@overridevoid reassemble() {super.reassemble();debugPrint("reassemble");}@overridevoid didChangeDependencies() {super.didChangeDependencies();debugPrint("didChangeDependencies");}}
运行应用控制台日志输出,在StatefulWidget插入到 widget 树时首先initState方法会被调用。
flutter: initStateflutter: didChangeDependenciesflutter: build
点击⚡️按钮热重载,控制台输出日志如下,initState 和didChangeDependencies都没有被调用
flutter: reassembleflutter: build
接下来,我们在 widget 树中移除MyHomePage,将 MyApp 的 build方法改为:
class MyApp extends StatelessWidget {const MyApp({Key? key}) : super(key: key);@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',theme: ThemeData(primarySwatch: Colors.blue,),home: const Text("Flutter"),);}}
点击⚡️按钮热重载,控制台输出日志如下,在MyHomePage从 widget 树中移除时,deactive和dispose会依次被调用。
flutter: reassembleflutter: deactivateflutter: 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 生命周期如图:
