Flutter Weight笔记

Flutter 中是通过 Widget 嵌套 Widget 的方式来构建UI和进行事件处理的,所以记住,Flutter 中万物皆为Widget

Widget生命周期

initState

Widget 第一次插入到 Widget 树时会被调用,对于每一个State对象,Flutter 框架只会调用一次该回调,所以,通常在该回调中做一些一次性的操作,如状态初始化、订阅子树的事件通知等。不能在该回调中调用BuildContext.dependOnInheritedWidgetOfExactType(该方法用于在 Widget 树上获取离当前 Widget 最近的一个父级InheritedWidget,关于InheritedWidget我们稍后介绍,原因是在初始化完成后, Widget 树中的InheritFromWidget也可能会发生变化,所以正确的做法应该在在build()方法或didChangeDependencies()中调用它。

didChangeDependencies()

State对象的依赖发生变化时会被调用;例如:在之前build() 中包含了一个InheritedWidget ,然后在之后的build()InheritedWidget发生了变化,那么此时InheritedWidget的子 WidgetdidChangeDependencies()回调都会被调用。典型的场景是当系统语言 Locale 或应用主题改变时,Flutter 框架会通知 Widget 调用此回调。需要注意,组件第一次被创建后挂载的时候(包括重创建)对应的didChangeDependencies也会被调用。

build()

此回调读者现在应该已经相当熟悉了,它主要是用于构建 widget 子树的,会在如下场景被调用:
在调用initState()之后。
在调用didUpdateWidget()之后。
在调用setState()之后。
在调用didChangeDependencies()之后。
State对象从树中一个位置移除后(会调用·deactivate·)又重新插入到树的其他位置之后。
reassemble():此回调是专门为了开发调试而提供的,在热重载(hot reload)时会被调用,此回调在Release模式下永远不会被调用。

didUpdateWidget()

Widget 重新构建时,Flutter 框架会调用widget.canUpdate来检测 Widget 树中同一位置的新旧节点,然后决定是否需要更新,如果widget.canUpdate返回true则会调用此回调。正如之前所述,widget.canUpdate会在新旧 Widget 的 key 和 runtimeType 同时相等时会返回true,也就是说在在新旧 Widget 的key和runtimeType同时相等时didUpdateWidget()就会被调用。

deactivate()

State 对象从树中被移除时,会调用此回调。在一些场景下,Flutter 框架会将 State 对象重新插到树中,如包含此 State 对象的子树在树的一个位置移动到另一个位置时(可以通过GlobalKey 来实现)。如果移除后没有重新插入到树中则紧接着会调用dispose()方法。

dispose()

State 对象从树中被永久移除时调用;通常在此回调中释放资源。

生命周期

组件库介绍

Flutter 提供了一套丰富、强大的基础组件,在基础组件库之上 Flutter 又提供了一套 Material 风格( Android 默认的视觉风格)和一套 Cupertino 风格(iOS视觉风格)的组件库。

基础组件库导入:

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

Material(安卓风格)组件,需要先引入它:

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

Cupertino(iOS风格)组件,需要先引入它:

1
2
import 'package:flutter/cupertino.dart';

由于 MaterialCupertino 都是在基础组件库之上的,所以如果我们的应用中引入了这两者之一,则不需要再引入flutter/widgets.dart了,因为它们内部已经引入过了。

Flutter 的 Widget 类型分为StatefulWidgetStatelessWidget 两种,需要深入理解它们的区别,Widget 将是我们构建Flutter应用的基石。

状态管理

响应式的编程框架中都会有一个永恒的主题——“状态(State)管理”,无论是在 React/Vue(两者都是支持响应式编程的 Web 开发框架)还是 Flutter 中,他们讨论的问题和解决的思想都是一致的。
管理状态的最常见的方法:

  • Widget 管理自己的状态。
  • Widget 管理子 Widget 状态。
  • 混合管理(父 Widget 和子 Widget 都管理状态)。

如何决定使用哪种管理方法?下面是官方给出的一些原则可以帮助你做决定:

  • 如果状态是用户数据,如复选框的选中状态、滑块的位置,则该状态最好由父 Widget 管理。
  • 如果状态是有关界面外观效果的,例如颜色、动画,那么状态最好由 Widget 本身来管理。
  • 如果某一个状态是不同 Widget 共享的则最好由它们共同的父 Widget 管理。

InheritedWidget

InheritedWidget 是 Flutter 中非常重要的一个 Widget,它用于在 Widget 树中共享数据和状态。它提供了一种更高效的方式来将数据传递给子 Widget,避免直接将数据作为参数一层层传递。下面会详细介绍 InheritedWidget 的作用、用法、以及它的内部机制。

基本概念

InheritedWidget 主要用于构建 Flutter 应用中的数据共享和状态管理。它的工作原理是通过一个继承自 InheritedWidget 的自定义 Widget,来封装需要共享的数据。然后,所有需要使用这些数据的子 Widget,可以通过 BuildContext 获取这个 InheritedWidget 中的数据。

核心特点

  • 数据共享:它在 Widget 树的上层放置数据源,树中需要访问数据的子 Widget 通过上下文进行访问。
  • 高效的刷新机制:当数据发生变化时,只有依赖了该数据的 Widget 会被重新构建。

主要属性和方法

updateShouldNotify

这是一个必须实现的方法,用于确定当 InheritedWidget 更新时,是否需要通知其依赖的子 Widget。通常会比较新旧数据来决定是否需要更新:

1
2
3
4
@override
bool updateShouldNotify(covariant MyInheritedWidget oldWidget) {
return oldWidget.data != data; // 当数据变化时返回 true
}

of 方法

这是一个常见的静态方法,用于在子 Widget 中获取 InheritedWidget。在实现中,通常会调用 BuildContextdependOnInheritedWidgetOfExactType 方法:

1
2
3
static MyInheritedWidget? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
}

使用场景

  • 全局状态管理:在应用中某些状态或配置数据需要被多个 Widget 使用,例如用户设置、主题、语言等。
  • 数据传递与优化:减少大量的 setState 重建,尤其在 Widget 树比较深时,可以大大提升性能。

内部机制与原理

InheritedWidget 的工作原理主要基于 Flutter 框架的重建机制。当你调用 dependOnInheritedWidgetOfExactType 时,Flutter 会把当前 Widget 标记为依赖于某个特定的 InheritedWidget。如果该 InheritedWidget 发生变化(即 updateShouldNotify 返回 true),Flutter 将会触发依赖的 Widget 重新构建。

InheritedWidget 提供了一种高效且优雅的在 Widget 树中共享数据的方法,避免了直接将数据层层传递的复杂性。通过合理使用 InheritedWidget,可以显著减少不必要的重建,提升应用的性能。

Flutter非常流程新的框架 Provider 实际上是基于 InheritedWidget 进行封装的,是对它的一个高层抽象,目的是简化状态管理。