前言
果然了解的越多,越发现自己狗屁都不是。StatefulBuilder
和 Builder
之前真的不知道。还是在 对话框状态管理
中了解到了这两个东西。
简介
以下内容来自通义灵码
在Flutter中,StatefulBuilder
和 Builder
都是用来动态构建 widget 树的组件,但它们在处理状态管理和构建上下文方面有所不同:
StatefulBuilder
StatefulBuilder
是一个特殊的 widget,主要用于那些本身不是 StatefulWidget 但却需要在构建过程中更改和反应状态变化的场景。它接收一个 builder 函数作为参数,这个函数会在状态更改时被调用并重新构建其内部 widget 树。- 使用
StatefulBuilder
时,你可以直接在其 builder 方法内调用提供的_setState
参数来更新局部状态,并立即触发内部 widget 树的重建,而无需刷新整个页面或父级 StatefulWidget 的状态。
StatefulBuilder(builder: (BuildContext context, void Function(void Function()) setState) {bool isChecked = ...; // 可变状态return Checkbox(value: isChecked,onChanged: (bool newValue) {setState(() {isChecked = newValue;});},);},
);
Builder
Builder
widget 不具备自身的状态管理能力,但它主要用于构建作用域内的BuildContext,特别是在涉及到InheritedWidget、Theme、Navigator等需要访问新构建环境的场景下。Builder
主要用于将现有的 build 方法内部的上下文传递给其内部的 builder 函数,这样就可以在新的上下文中构建子 widget。这有助于隔离环境影响,尤其是在处理多个嵌套的Consumer
,StreamBuilder
或者InheritedWidget
时。
Builder(builder: (BuildContext context) {// 这里可以使用新的BuildContext来构建子widgetreturn Container(...);},
)
简而言之:
StatefulBuilder
允许你在没有独立 StatefulWidget 的情况下,在 widget 树的任何位置动态地更新状态。Builder
则是为了获取或创建一个新的构建上下文,以便于在不同的环境中正确构建和访问 widget。它本身不涉及状态管理,更多关注的是构建环境的控制与传递。
案例
上面那篇文章里有对应的例子。这里也只是对其记录和学习。
Future<bool?> showDeleteDialog() {// 记录是否选中bool isChecked = true;return showDialog<bool>(context: context,builder: (context) {return AlertDialog(title: const Text("提示"),content: Column(crossAxisAlignment: CrossAxisAlignment.start,// 高度设置为最小mainAxisSize: MainAxisSize.min,children: [const Text("是否删除?"),Row(children: [const Text("同时删除子目录?"),Checkbox(value: isChecked,onChanged: (bool? value) {isChecked = value!;})],)],),actions: [TextButton(onPressed: () {Navigator.pop(context, false);},child: const Text("取消")),TextButton(onPressed: () {// 返回选中状态Navigator.pop(context, isChecked);},child: const Text("确定")),],);});}
可以看出,UI没有被更新,文章中也给出了解释:
对话框也是通过路由的方式来实现的,那么上面的代码实际上就等同于企图在父路由中调用setState来让子路由更新,这显然是不行的!简尔言之,根本原因就是context不对。
解决方法那就是使用 StatefulBuilder
和 Builder
获取到独立的context
Row(children: [const Text("同时删除子目录?"),StatefulBuilder(builder: (context, setState) {return Checkbox(value: isChecked,onChanged: (bool? value) {setState(() {isChecked = value!;});});})],
)
Row(children: [const Text("同时删除子目录?"),Builder(builder: (context) {return Checkbox(value: isChecked,onChanged: (bool? value) {(context as Element).markNeedsBuild();isChecked = value ?? false;});})],)
StatefulBuilder
中会提供一个setState
用来更新局部状态,触发UI更新。
Builder
则是为了获取或创建一个新的构建上下文,调用Element
的markNeedsBuild()
方法来进行局部状态更新。