Flutter 之学习摘要

1、Widget 只是Flutter 对UI元素的一种描述配置

在 Flutter 中, widget 的功能是"描述一个UI元素的配置信息",它就是说, Widget 其实并不是表示最终绘制在设备屏幕上的显示元素

@immutable 代表 Widget 是不可变的,这会限制 Widget 中定义的属性(即配置信息)必须是不可变的(final),为什么不允许 Widget 中定义的属性变化呢?这是因为,Flutter 中如果属性发生变化则会重新构建Widget树,即重新创建新的 Widget 实例来替换旧的 Widget 实例

widget 的属性应尽可能的被声明为final,防止被意外改变。

1.2 Context

context是当前 widget 在 widget 树中位置中执行"相关操作"的一个句柄(handle)

ini 复制代码
 // 在 widget 树中向上查找最近的父级`Scaffold`  widget 
 Scaffold scaffold = context.findAncestorWidgetOfExactType<Scaffold>();

context对象有一个findAncestorStateOfType()方法,该方法可以从当前节点沿着 widget 树向上查找指定类型的 StatefulWidget 对应的 State 对象。

ini 复制代码
// 查找父级最近的Scaffold对应的ScaffoldState对象
ScaffoldState _state = context.findAncestorStateOfType<ScaffoldState>()!;
// 打开抽屉菜单
_state.openDrawer();

of 方法

在 Flutter 开发中便有了一个默认的约定:如果 StatefulWidget 的状态是希望暴露出的,应当在 StatefulWidget 中提供一个of 静态方法来获取其 State 对象,开发者便可直接通过该方法来获取;如果 State不希望暴露,则不提供of方法。

ini 复制代码
 // 直接通过of静态方法来获取ScaffoldState
 ScaffoldState _state=Scaffold.of(context);
 // 打开抽屉菜单
 _state.openDrawer();
less 复制代码
  //又比如我们想显示 snack bar 的话可以通过下面代码调用
  ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text("我是SnackBar")),
      );
1.3 StatefulElementcreateState()

createState() 用于创建和 StatefulWidget 相关的状态,它在StatefulWidget 的生命周期中可能会被多次调用。例如,当一个 StatefulWidget 同时插入到 widget 树的多个位置时,Flutter 框架就会调用该方法为每一个位置生成一个独立的State实例,
其实,本质上就是一个 StatefulElement 对应一个State实例。

而在StatefulWidget 中,State 对象和StatefulElement具有一一对应的关系,所以在Flutter的SDK文档中,可以经常看到"从树中移除 State 对象"或"插入 State 对象到树中"这样的描述,此时的树指通过 widget 树生成的 Element 树。

1.4 State

widget,它表示与该 State 实例关联的 widget 实例,由Flutter 框架动态设置。注意,这种关联并非永久的,因为在应用生命周期中,UI树上的某一个节点的 widget 实例在重新构建时可能会变化,但State实例只会在第一次插入到树中时被创建,当在重新构建时,如果 widget 被修改了,Flutter 框架会动态设置State. widget 为新的 widget 实例。

State 生命周期

Flutter State生命周期
Flutter之 State 生命周期

State 对象获取

1、参考上面的Context

2、参考上面的Context

3、通过GlobalKey

globalKey.currentWidget

globalKey.currentElement

globalKey.currentState

注意:使用 GlobalKey 开销较大,如果有其他可选方案,应尽量避免使用它。另外,同一个 GlobalKey 在整个 widget 树中必须是唯一的,不能重复。

2、Flutter中的四棵树 ( Widget树、Element树、渲染树、Layer树 )

既然 Widget 只是描述一个UI元素的配置信息,那么真正的布局、绘制是由谁来完成的呢?Flutter 框架的处理流程是这样的:

  1. 根据 Widget 树生成一个 Element 树,Element 树中的节点都继承自 Element 类。
  2. 根据 Element 树生成 Render 树(渲染树),渲染树中的节点都继承自RenderObject 类。
  3. 根据渲染树生成 Layer 树,然后上屏显示,Layer 树中的节点都继承自 Layer 类。

真正的布局和渲染逻辑在 Render 树中,Element 是 Widget 和 RenderObject 的粘合剂,可以理解为一个中间代理。

这里需要注意:

  1. 三棵树中,Widget 和 Element 是一一对应的,但并不和 RenderObject 一一对应。比如 StatelessWidgetStatefulWidget 都没有对应的 RenderObject。
  2. 渲染树在上屏前会生成一棵 Layer 树,这个我们将在后面原理篇介绍,在前面的章节中读者只需要记住以上三棵树就行。

3 assets 加载图片

类似于原生开发,Flutter也可以为当前设备加载适合其分辨率的图像。

#1)声明分辨率相关的图片 assets

AssetImage (opens new window)可以将asset的请求逻辑映射到最接近当前设备像素比例(dpi)的asset。为了使这种映射起作用,必须根据特定的目录结构来保存asset:

  • .../image.png
  • .../Mx/image.png
  • .../Nx/image.png
  • ...

其中 M 和 N 是数字标识符,对应于其中包含的图像的分辨率,也就是说,它们指定不同设备像素比例的图片。

主资源默认对应于1.0倍的分辨率图片。看一个例子:

  • .../my_icon.png
  • .../2.0x/my_icon.png
  • .../3.0x/my_icon.png

在设备像素比率为1.8的设备上,.../2.0x/my_icon.png 将被选择。对于2.7的设备像素比率,.../3.0x/my_icon.png将被选择。

如果未在Image widget上指定渲染图像的宽度和高度,那么Image widget将占用与主资源相同的屏幕空间大小。 也就是说,如果.../my_icon.png是72px乘72px,那么.../3.0x/my_icon.png应该是216px乘216px; 但如果未指定宽度和高度,它们都将渲染为72像素×72像素(以逻辑像素为单位)。

pubspec.yaml中asset部分中的每一项都应与实际文件相对应,但主资源项除外。当主资源缺少某个资源时,会按分辨率从低到高的顺序去选择 ,也就是说1x中没有的话会在2x中找,2x中还没有的话就在3x中找。

4、异常处理:

在事件循环中,当某个任务发生异常并没有被捕获时,程序并不会退出,而直接导致的结果是当前任务的后续代码就不会被执行了,也就是说一个任务中的异常是不会影响其他任务执行的。

5、Flutter 中有两种布局模型:

  • 基于 RenderBox 的盒模型布局。
  • 基于 Sliver ( RenderSliver ) 按需加载列表布局。

两种布局方式在细节上略有差异,但大体流程相同,布局流程如下:

  1. 上层组件向下层组件传递约束(constraints)条件。
  2. 下层组件确定自己的大小,然后告诉上层组件。注意下层组件的大小必须符合父组件的约束。
  3. 上层组件确定下层组件相对于自身的偏移和确定自身的大小(大多数情况下会根据子组件的大小来确定自身的大小)。

book.flutterchina.club/

相关推荐
醉の虾21 分钟前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧29 分钟前
TypeScript 的发展与基本语法
前端·javascript·typescript
hummhumm39 分钟前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
asleep7011 小时前
第8章利用CSS制作导航菜单
前端·css
hummhumm1 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
幼儿园的小霸王2 小时前
通过socket设置版本更新提示
前端·vue.js·webpack·typescript·前端框架·anti-design-vue
疯狂的沙粒2 小时前
对 TypeScript 中高级类型的理解?应该在哪些方面可以更好的使用!
前端·javascript·typescript
gqkmiss2 小时前
Chrome 浏览器 131 版本开发者工具(DevTools)更新内容
前端·chrome·浏览器·chrome devtools
Summer不秃2 小时前
Flutter之使用mqtt进行连接和信息传输的使用案例
前端·flutter
旭日猎鹰2 小时前
Flutter踩坑记录(二)-- GestureDetector+Expanded点击无效果
前端·javascript·flutter