为了支持使用静态的 ViewModel.update 方法来更新模型,我们需要引入额外一个额外的有状态组件。这会稍微有点复杂。
1.将 ModelBinding 变成了一个有状态组件,并且持有当前状态模型对象。
2.为ModelBinding 构建了一个_ModelBindingScope 的 InheritedWidget 子组件,该子组件引用了 State<ModelBinding>——即_ModelBingingState,其实就相当于是引用了父级的状态。
3.为了改变 ModelBinding 当前模型的值,从而在调用 setState 方法重建 ModelBinding,并重建下级的_ModelBindingScope。
4.通过_ModelBindingScope 来实现ViewModel类的静态获取模型对象及更新对象
static ViewModel of(BuildContext context) { _ModelBindingScope scope = context.dependOnInheritedWidgetOfExactType(aspect: _ModelBindingScope); return scope.modelBindingState.currentModel; } static void update(BuildContext context, ViewModel newModel) { _ModelBindingScope scope = context.dependOnInheritedWidgetOfExactType(aspect: _ModelBindingScope); scope.modelBindingState.updateModel(newModel); }现在,任何 ModelBinding 的子组件都可以使用这些方法来更新模型数据了,下面的按钮代码就同时获取和更新了模型的数据。
Widget build(BuildContext context) { return ElevatedButton( child: Text('Hello World ${ViewModel.of(context).value}'), onPressed: () { ViewModel model = ViewModel.of(context); ViewModel.update(context, ViewModel(value: model.value + 1)); }, ); }运行一下,一切正常(完整代码:model_binding_v1.dart),是不是该庆祝一下?然而,如果我们有技术上百个状态的话我们要写几十上百个 ModelBinding 类,而且每个 Model 都要提供一个静态的 of(context)和 update 方法?
class _ModelBindingScope<T> extends InheritedWidget { _ModelBindingScope({ Key key, @required this.modelBindingState, Widget child, }) : assert(modelBindingState != null), super(key: key, child: child); final _ModelBindingV2State<T> modelBindingState; @override bool updateShouldNotify(_ModelBindingScope oldWidget) => true; }改起来很简单,只需要加上泛型参数就好了。接下来是_ModelBindV2State,这个类也许改成泛型。
class _ModelBindingV2State<T> extends State<ModelBindingV2<T>> { T currentModel; @override void initState() { super.initState(); currentModel = widget.create(); } void updateModel(T newModel) { if (currentModel != newModel) { setState(() { currentModel = newModel; }); } } @override Widget build(BuildContext context) { return _ModelBindingScope<T>( modelBindingState: this, child: widget.child, ); } }实际上,也只是增加了泛型参数,这里有个地方需要注意的是,之前我们是在_ModelBidingV2State 中直接构建初始状态了,现在由于是泛型,我们没法直接构建泛型对象,因此需要从有状态组件中获取。这里我们在 initState 中调用了 ModeBinding 类的 create 方法返回一个泛型对象(当然,也可以直接使用赋值,取决于 ModelBinding 类如何获取初始状态对象)。
// 堆代码 duidaima.com class ModelBindingV2<T> extends StatefulWidget { ModelBindingV2({Key key, @required this.create, this.child}) : assert(create != null), super(key: key); final ValueGetter<T> create; final Widget child; @override _ModelBindingV2State<T> createState() => _ModelBindingV2State<T>(); static T of<T>(BuildContext context) { _ModelBindingScope<T> scope = context.dependOnInheritedWidgetOfExactType(aspect: _ModelBindingScope); return scope.modelBindingState.currentModel; } static void update<T>(BuildContext context, T newModel) { _ModelBindingScope<T> scope = context.dependOnInheritedWidgetOfExactType(aspect: _ModelBindingScope); scope.modelBindingState.updateModel(newModel); } }改造完成之后,我们的实际 Controller 的代码就变成下面这样了:
class StateViewControllerV2 extends StatelessWidget { StateViewControllerV2({Key key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('模型绑定泛型版'), ), body: Center( child: ModelBindingV2( create: () => ViewModel(), child: ViewController(), ), ), ); } } class ViewController extends StatelessWidget { const ViewController({Key key}) : super(key: key); @override Widget build(BuildContext context) { return ElevatedButton( child: Text('Hello World ${ModelBindingV2.of<ViewModel>(context).value}'), onPressed: () { ViewModel model = ModelBindingV2.of<ViewModel>(context); ModelBindingV2.update(context, ViewModel(value: model.value + 1)); }, ); } }可以看到,整个 ModelBinding 类完成了状态的获取和更新,而且适用于任何状态模型类。