如何管理弹窗中复选框的选中状态?习惯上,我们会在路由页的State中来管理选中状态,我们可能会:
setState(() {
//更新复选框状态
withTree = !withTree;
});
然后,当我们运行上面的代码时我们会发现复选框根本选不中!为什么会这样呢?其实原因很简单,我们知道setState方法只会针对当前context的子树重新build,但是我们的对话框并不是在_DialogRouteState的build 方法中构建的,而是通过showDialog单独构建的,所以在_DialogRouteState的context中调用setState是无法影响通过showDialog构建的UI的。另外,我们可以从另外一个角度来理解这个现象,前面说过对话框也是通过路由的方式来实现的,那么上面的代码实际上就等同于企图在父路由中调用setState来让子路由更新,这显然是不行的!简尔言之,根本原因就是context不对。那如何让复选框可点击呢?通常有如下三种方法:
一、单独抽离出StatefulWidget
缺点:对话框上所有可能会改变状态的组件都得单独封装在一个在内部管理状态的StatefulWidget中,这样不仅麻烦,而且复用性不大。
二、使用StatefulBuilder方法
自己的理解:实际上,这种方法本质上就是子组件通知父组件(StatefulWidget)重新build子组件本身来实现UI更新的。如果你需要改变的变量是全局的,那么这种方法就不会去改变全局的变量,就是作用域的问题。
//使用StatefulBuilder来构建StatefulWidget上下文
StatefulBuilder(
builder: (context, _setState) {
return Checkbox(
value: _withTree, //默认不选中
onChanged: (bool value) {
//_setState方法实际就是该StatefulWidget的setState方法,
//调用后builder方法会重新被调用
_setState(() {
//更新选中状态
_withTree = !_withTree;
});
},
);
},
),
三、精妙的解法,个人觉得这是最简单的方法
// 通过Builder来获得构建Checkbox的`context`,
// 这是一种常用的缩小`context`范围的方式
Builder(
builder: (BuildContext context) {
return Checkbox(
value: _withTree,
onChanged: (bool value) {
(context as Element).markNeedsBuild();
_withTree = !_withTree;
},
);
},
),