【Flutter 组件】001-关于 Widget 的一切

【Flutter 组件】001-关于 Widget 的一切

一、概述

1、Widget 基本概述

Flutter 中的 Widget 相当于 Android 里的 View,iOS 里的 UIView。

  • Flutter 中几乎所有的对象都是一个 **widget **;* Widget 不仅可以表示 UI 元素,还可以表示一些功能性的组件,如用于手势检测的 GestureDetector 、用于APP主题数据传递的 Theme 等等;* 我们将 Widget 统称为组件。> 界面刷新机制,类似 React

当 Widget 状态发生变化,需要更新界面时,框架会先计算从上一个状态转换到下一个状态所需的最小更改,然后再去刷新界面。

2、Flutter Framework 里的 Widget

架构图

说明

Framework 里面有一层是 Widgets,在 Widgets 层下面,有:

  • Rendering(渲染层)
  • Animation、Painting、Gestures(动画、绘制、手势)
  • Foundation(基础库层)

Widgets 层下面平常使用较少,也比较复杂,常用 Widgets 层上面的 Material 和 Cupertino。

摘录:Material & Cupertino 指的 Widget 的风格是 Material 或 Cupertino 。Flutter 为了减轻开发人员的工作量,实现了两种不同风格的组件:Material 和 Cupertino 。**Material 用于 Android,Cupertino 用于 iOS。**有了这些组件,开发人员不需要再做额外的工作,就可以让 Flutter 的 UI 风格适应不同的平台,让 Flutter UI 获得和 Native UI 一样的使用体验。

3、根 Widget

我们常用的 MaterialApp 就是根(Root)Widget ,Flutter会默认把 根Widget 充满屏幕。

根 Widget 只能是下面三个:

  • WidgetsAppWidgetsApp 是可以自定义风格的 根Widget。* MaterialAppMaterialApp 是在 WidgetsApp 上添加了很多 material-design 的功能,是 Material Design 风格的 根Widget。* CupertinoAppCupertinoApp 也是基于 WidgetsApp 实现的 iOS 风格的 根Widget。MaterialApp 是最常用的,也是功能最完善的,且经常与 Scaffold 一起使用。

二、Widget 类

1、Widget 的功能

描述一个UI元素的配置信息

就是说, Widget 其实并不是表示最终绘制在设备屏幕上的显示元素,所谓的配置信息就是 Widget 接收的参数,比如对于 Text 来讲,文本的内容、对齐方式、文本样式都是它的配置信息。

Widget 描述了他们的视图在给定其当前配置和状态时应该看起来像什么。

2、Widget 类

源码

@immutable
abstract class Widget extends DiagnosticableTree {const Widget({ this.key });final Key? key;@protected@factoryElement createElement();@overrideString toStringShort() {final String type = objectRuntimeType(this, 'Widget');return key == null ? type : '$type-$key';}@overridevoid debugFillProperties(DiagnosticPropertiesBuilder properties) {super.debugFillProperties(properties);properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;}@override@nonVirtualbool operator ==(Object other) => super == other;@override@nonVirtualint get hashCode => super.hashCode;static bool canUpdate(Widget oldWidget, Widget newWidget) {return oldWidget.runtimeType == newWidget.runtimeType&& oldWidget.key == newWidget.key;}static int _debugConcreteSubtype(Widget widget) {return widget is StatefulWidget ? 1 : widget is StatelessWidget ? 2 : 0;}
} 

说明

Widget 类本身是一个抽象类,其中最核心的就是定义了 createElement() 接口。我们在开发中一般不直接继承 Widget 而是 Widget 的子类:StatelessWidgetStatefulWidget来间接继承widget类。

  • @immutable :代表 Widget 是不可变的,这会限制 Widget 中定义的属性(即配置信息)必须是不可变的(final)为什么?因为 Flutter 中的属性发生变化会导致重新构建 Widget 树,即重新创建新的 Widget 实例来替换旧的 Widget 实例,所以允许 Widget 的属性变化是没有意义的,因为一旦 Widget 自己的属性变了自己就会被替换。* widget 类继承自 DiagnosticableTreeDiagnosticableTree即“诊断树”,主要作用是提供调试信息。* Key : 这个key属性类似于 React/Vue 中的key,主要的作用是决定是否在下一次 build复用旧的 widget ,决定的条件在canUpdate()方法中。* createElement() :正如前文所述“一个 widget 可以对应多个Element”;Flutter 框架在构建UI树时,会先调用此方法生成对应节点的Element对象。 此方法是 Flutter 框架隐式调用的,在我们开发过程中基本不会调用到。* debugFillProperties(...) 复写父类的方法,主要是设置诊断树的一些特性。* canUpdate(...) 是一个静态方法,它主要用于在 widget 树重新 build复用旧的 widget ,其实具体来说,应该是:是否用新的 widget 对象去更新旧 UI 树上所对应的 Element 对象的配置;通过其源码我们可以看到,只要 newWidgetoldWidgetruntimeTypekey 同时相等时就会用 new widget 去更新 Element 对象的配置,否则就会创建新的 Element 。### Widget 的标识符:Key

diff 简介: 因为 Flutter 采用的是 react-style 的框架,每次刷新 UI 的时候,都会重新构建新的 Widget树,然后和之前的 Widget树 进行对比计算出变化的部分,这个计算过程叫做 diff 。

标识符: 在 diff 过程中,如果能提前知道哪些 Widget 没有变化,无疑会提高 diff 的性能,这时候就需要使用到标识符

为了在 diff 过程中,知道 Widget 有没有变化,就需要给 Widget 添加一个唯一的标识符,然后在 Widget树 的 diff 过程中,查看刷新前后的 Widget树 有没有相同标识符的 Widget,如果标识符相同,则说明 Widget 没有变化否则说明 Widget 有变化

假设 UI 刷新前,Widget树 是 A,在 A 里有一个标识符为 a 的 Widget,在 UI 刷新后,重建的 Widget树 是 B,如果 B 里还有标识符为 a 的 Widget,则说明这个 Widget 没变,但是如果 B 里没有标识符为 a 的 Widget,那么说明这个 Widget 发生了变化。

这个标识符在 Flutter 中就是 Key所有 Widget 都有 Key 这一个属性。

Flutter 中如何在 diff 过程中判断哪些 Widget 没有变化

稍微有些复杂,有两种情况:

  • 默认情况下( Widget 没有设置 Key)当没有给 Widget 设置 Key 时,Flutter 会根据 Widget 的 runtimeType 和显示顺序是否相同来判断 Widget 是否有变化。runtimeType 是 Widget 的类型,例如 Text 和 RaisedButton 就是不同的类型。* Widget 有 Key当给 Widget 设置了 Key 时,Flutter 是根据 Key 和 runtimeType 是否相同来判断 Widget 是否有变化。### Key 的分类

Key 总共分为两类:

1.Local Key(局部Key)
2.Global Key(全局Key)

1. Local Key(局部Key)

在有相同父级的 Widget 中,Key 必须是唯一的,这样的 Key 叫做 局部 Key。

局部Key 在 Flutter 中对应的抽象类是 LocalKey。LocalKey 有不同的实现,主要的区别就是使用什么值来作为 Key 的值:

  • ObjectKey将对象作为 Key 的值。* ValueKey使用特定类型的值来作为 Key 的值。* UniqueKey使用 UniqueKey 自己的对象作为 Key 的值,所以只与自身相等
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值