原文地址: https://www.jianshu.com/p/0687b41dc80c

背景

我们知道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 { @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”); } }

简单来说,Nested在build方法中,倒序遍历children,将每个item转换成_NestedHook对象。
并在遍历的过程中,将倒序排序中的前节点(我们后面所说的子节点)注入到每个item里面。第一个item注入的是Nested的child对象,其他item注入的是children队列中的前一个节点元素。
最终,注入的child,会响应在各自 buildWithChild方法中,作为入参存在。
Widget body() { return AWidget( child: BWidget( child: CWidget(), ), ); }
我们发现,在嵌套层数不多时,代码阅读性并没有受到太大的影响。但当嵌套关系变得复杂时,会严重影响编码体验。

处理 flutter 嵌套过深的利器 Nested

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 { @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结构简图

我们用 Demo 中的样例画了一张简图,整个过程更加清晰:

我们常用的 providerbloc 这两个库也是使用的 Nested 来处理代码的嵌套深渊

作者:李小轰
链接:https://www.jianshu.com/p/0687b41dc80c
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。