一、创建工程

环境安装配置好后,打开Android Studio开发工具,选择Flutter,确认Flutter SDK path,点击Next。
WX20220702-183433@2x.png
选择Projects,点击New Flutter Project,新建Flutter项目。
WX20220702-183311@2x.png
设置Project name、Project location、Android language、iOS language后点击Finish,生成项目工程。

  • Project name:项目名称
  • Project location :项目本地路径
  • Android language:安卓开发语言
  • iOS language:iOS开发语言

WX20220702-183727@2x.png

二、代码分析

2.1 runApp

runApp是Flutter内部提供的一个函数,当启动一个Flutter应用程序时就是从调用此函数开始,runApp的函数定义如下:

  1. void runApp(Widget app) {
  2. ...
  3. }

需要我们传入一个Widget,那什么是Widget呢?

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 组件,需要先引入它:

  1. import 'package:flutter/material.dart';

MyApp中build返回的是MaterialApp,整个应用采用MaterialApp风格,其中三个属性:

  • title:应用程序的描述标题,可以不写;
  • theme:用于配置应用的主题;
  • home:应用启动时显示的页面;

    1. class MyApp extends StatelessWidget {
    2. const MyApp({Key? key}) : super(key: key);
    3. @override
    4. Widget build(BuildContext context) {
    5. return MaterialApp(
    6. title: 'Flutter Demo',
    7. theme: ThemeData(
    8. primarySwatch: Colors.blue,
    9. ),
    10. home: const MyHomePage(title: 'Flutter Demo Home Page'),
    11. );
    12. }
    13. }

    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(

    1. title: 'Flutter Demo',
    2. theme: ThemeData(
    3. primarySwatch: Colors.blue,
    4. ),
    5. 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示例程序缩减代码:

  1. class MyHomePage extends StatefulWidget {
  2. const MyHomePage({Key? key, required this.title}) : super(key: key);
  3. final String title;
  4. @override
  5. State<MyHomePage> createState() => _MyHomePageState();
  6. }
  7. class _MyHomePageState extends State<MyHomePage> {
  8. int _counter = 0;
  9. void _incrementCounter() {...}
  10. @override
  11. Widget build(BuildContext context) {
  12. return Scaffold(...)
  13. }
  14. }

四、生命周期

什么是生命周期,在Flutter中是一个组件的创建到销毁的的过程
StatelessWidget 组件生命周期函数 : 只有 createElement()、build() 两个函数 ;

  1. abstract class StatelessWidget extends Widget {
  2. const StatelessWidget({ Key? key }) : super(key: key);
  3. @override
  4. StatelessElement createElement() => StatelessElement(this);
  5. @protected
  6. Widget build(BuildContext context);
  7. }

StatefulWidget需要通过State来管理数据,监控状态的改变决定是否重新build整个Widget;我们主要讨论StatefulWidget的生命周期,还是以Flutter示例程序为例:

  1. class MyHomePage extends StatefulWidget {
  2. const MyHomePage({Key? key, required this.title}) : super(key: key);
  3. final String title;
  4. @override
  5. State<MyHomePage> createState() => _MyHomePageState();
  6. }
  7. class _MyHomePageState extends State<MyHomePage> {
  8. int _counter = 0;
  9. @override
  10. void initState() {
  11. super.initState();
  12. debugPrint("initState");
  13. }
  14. void _incrementCounter() {...}
  15. @override
  16. Widget build(BuildContext context) {
  17. debugPrint("build");
  18. return Scaffold(...);
  19. }
  20. @override
  21. void didUpdateWidget(covariant MyHomePage oldWidget) {
  22. super.didUpdateWidget(oldWidget);
  23. debugPrint("didUpdateWidget");
  24. }
  25. @override
  26. void deactivate() {
  27. super.deactivate();
  28. debugPrint("deactivate");
  29. }
  30. @override
  31. void dispose() {
  32. super.dispose();
  33. debugPrint("dispose");
  34. }
  35. @override
  36. void reassemble() {
  37. super.reassemble();
  38. debugPrint("reassemble");
  39. }
  40. @override
  41. void didChangeDependencies() {
  42. super.didChangeDependencies();
  43. debugPrint("didChangeDependencies");
  44. }
  45. }

运行应用控制台日志输出,在StatefulWidget插入到 widget 树时首先initState方法会被调用。

  1. flutter: initState
  2. flutter: didChangeDependencies
  3. flutter: build

点击⚡️按钮热重载,控制台输出日志如下,initState 和didChangeDependencies都没有被调用

  1. flutter: reassemble
  2. flutter: build

接下来,我们在 widget 树中移除MyHomePage,将 MyApp 的 build方法改为:

  1. class MyApp extends StatelessWidget {
  2. const MyApp({Key? key}) : super(key: key);
  3. @override
  4. Widget build(BuildContext context) {
  5. return MaterialApp(
  6. title: 'Flutter Demo',
  7. theme: ThemeData(
  8. primarySwatch: Colors.blue,
  9. ),
  10. home: const Text("Flutter"),
  11. );
  12. }
  13. }

点击⚡️按钮热重载,控制台输出日志如下,在MyHomePage从 widget 树中移除时,deactive和dispose会依次被调用。

  1. flutter: reassemble
  2. flutter: deactivate
  3. 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 生命周期如图:
截屏2022-07-03 22.06.28.png