使用 `Nested` 处理 flutter 嵌套过深
2021-09-02 本文已影响0人
李小轰
背景
我们知道flutter
是一种声明式的开发模式。编写代码时,widget
一层嵌套一层,最后在Render
层进行整理汇总后,完成绘制。这种嵌套的设计模式,在视觉上,往往会让我们产生疲惫感。
嵌套现象
如下,我们声明三个Widget,并把它们三个进行嵌套排列:
///第一层父节点
class AWidget extends StatefulWidget {
final Widget child;
const AWidget({Key key, @required this.child}) : super(key: key);
@override
_AWidgetState createState() => _AWidgetState();
}
class _AWidgetState extends State<AWidget> {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
color: Colors.blue,
child: widget.child,
);
}
}
///第二层父节点
class BWidget extends StatelessWidget {
final Widget child;
const BWidget({Key key, @required this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
color: Colors.yellow,
child: child,
);
}
}
///第三层子节点
class CWidget extends StatelessWidget {
const CWidget({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text("child C");
}
}
///嵌套排列
Widget body() {
return AWidget(
child: BWidget(
child: CWidget(),
),
);
}
我们发现,在嵌套层数不多时,代码阅读性并没有受到太大的影响。但当嵌套关系变得复杂时,会严重影响编码体验。
处理 flutter 嵌套过深的利器 Nested
- pub 添加引用
nested: ^1.0.0
使用方式
我们使用Nested
对上面的Demo进行优化修改:
-
AWidget
和BWidget
需要分别继承SingleChildStatefulWidget
,SingleChildState
和SingleChildStatelessWidget
///第一层父节点
class AWidget extends SingleChildStatefulWidget {
const AWidget({Key key}) : super(key: key);
@override
_AWidgetState createState() => _AWidgetState();
}
class _AWidgetState extends SingleChildState<AWidget> {
@override
Widget buildWithChild(BuildContext context, Widget child) {
// 这里接收到的 child 就是 BWidget
return Container(
padding: EdgeInsets.all(10),
color: Colors.blue,
child: child,
);
}
}
///第二层父节点
class BWidget extends SingleChildStatelessWidget {
const BWidget({Key key}) : super(key: key);
@override
Widget buildWithChild(BuildContext context, Widget child) {
// 这里接收到的 child 就是 CWidget
return Container(
padding: EdgeInsets.all(10),
color: Colors.yellow,
child: child,
);
}
}
继承后,需要实现 buildWithChild
方法,方法内 child
入参是 Nested 框架层处理注入的子节点[ 分别是 demo 中的 CWidget 和 BWidget ]。(实现原理我们在文末来聊)
- 子节点关系是如何表述的呢?
Widget body() {
return Nested(
children: [
AWidget(),
BWidget(),
],
child: CWidget(),
);
}
代码说明:
按照倒序关系:
CWidget
作为 child
响应在 BWidget
的 buildWithChild
方法中;
BWidget
作为 child
响应在 AWidget
的 buildWithChild
方法中。
注意点: Nested
的 children
数组要求元素必须是 SingleChildWidget
的子类
开发便利贴:
Nested
为我们提供如下工具类,已实现继承SingleChildWidget
。前两种方式需要基础并重写buildWithChild
方法。
- 对应StatelessWidget:
SingleChildStatelessWidget
- 对应StatefulWidget:
SingleChildStatefulWidget
+SingleChildState
- 便捷方式,无需继承:
SingleChildBuilder
Nested 实现原理分析
Nested结构简图简单来说,Nested 在 build 方法中,倒序遍历
children
,将每个 item
转换成 _NestedHook
对象。并在遍历的过程中,将倒序排序中的前节点(我们后面所说的子节点)注入到每个
item
里面。第一个 item
注入的是 Nested
的 child
对象,其他 item
注入的是children
队列中的前一个节点元素。最终,注入的
child
,会响应在各自 buildWithChild
方法中,作为入参存在。
我们用 Demo 中的样例画了一张简图,整个过程更加清晰:
我们常用的
provider
bloc
这两个库也是使用的Nested
来处理代码的嵌套深渊
关于Flutter嵌套优化,小轰看到过另一种思路,这里也分享给大家 Flutter嵌套优化