Created
December 15, 2018 00:20
-
-
Save HansMuller/29b03fc5e2285957ad7b0d6a58faac35 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This version of the example adds a static Model method for updating the | |
ModelBinding's current model value: | |
``` | |
Model.update(context, newModel); | |
``` | |
This substantially reduces the plumbing required for widgets that need to | |
changes the app's model. Instead of passing down a callback that rebuilds the | |
ModelBinding, any widget can update the ModelBinding's current state directly. | |
The stateless ViewController now handles a button press like this: | |
``` | |
onPressed: () { | |
final Model model = Model.of(context); | |
Model.update(context, Model(value: model.value + 1)); | |
} | |
``` | |
The implementation of this feature is a little tricky. ModelBinding is now | |
a stateful widget that tracks the current Model value. ModelBinding | |
builds an _ModelBindingScope InheritedWidget child that has pointer to the | |
State<ModelBinding> - an _ModelBindingState; essentially to its stateful widget | |
(ModelBinding) parent. To update change ModelBinding's current Model value, | |
we rebuild the ModelBinding with setState(). | |
*/ | |
import 'package:flutter/material.dart'; | |
class Model { | |
const Model({ this.value = 0 }); | |
final int value; | |
@override | |
bool operator ==(Object other) { | |
if (identical(this, other)) | |
return true; | |
if (other.runtimeType != runtimeType) | |
return false; | |
final Model otherModel = other; | |
return otherModel.value == value; | |
} | |
@override | |
int get hashCode => value.hashCode; | |
static Model of(BuildContext context) { | |
final _ModelBindingScope scope = context.inheritFromWidgetOfExactType(_ModelBindingScope); | |
return scope.modelBindingState.currentModel; | |
} | |
static void update(BuildContext context, Model newModel) { | |
final _ModelBindingScope scope = context.inheritFromWidgetOfExactType(_ModelBindingScope); | |
scope.modelBindingState.updateModel(newModel); | |
} | |
} | |
class _ModelBindingScope extends InheritedWidget { | |
_ModelBindingScope({ | |
Key key, | |
@required this.modelBindingState, | |
Widget child, | |
}) : assert(modelBindingState != null), super(key: key, child: child); | |
final _ModelBindingState modelBindingState; | |
@override | |
bool updateShouldNotify(_ModelBindingScope oldWidget) => true; | |
} | |
class ModelBinding extends StatefulWidget { | |
ModelBinding({ | |
Key key, | |
this.initialModel = const Model(), | |
this.child, | |
}) : assert(initialModel != null), super(key: key); | |
final Model initialModel; | |
final Widget child; | |
_ModelBindingState createState() => _ModelBindingState(); | |
} | |
class _ModelBindingState extends State<ModelBinding> { | |
Model currentModel; | |
@override | |
void initState() { | |
super.initState(); | |
currentModel = widget.initialModel; | |
} | |
void updateModel(Model newModel) { | |
if (newModel != currentModel) { | |
setState(() { | |
currentModel = newModel; | |
}); | |
} | |
} | |
@override | |
Widget build(BuildContext context) { | |
return _ModelBindingScope( | |
modelBindingState: this, | |
child: widget.child, | |
); | |
} | |
} | |
class ViewController extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return RaisedButton( | |
onPressed: () { | |
final Model model = Model.of(context); | |
Model.update(context, Model(value: model.value + 1)); | |
}, | |
child: Text('Hello World ${Model.of(context).value}'), | |
); | |
} | |
} | |
class App extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
home: ModelBinding( | |
initialModel: const Model(), | |
child: Scaffold( | |
body: Center( | |
child: ViewController(), | |
), | |
), | |
), | |
); | |
} | |
} | |
void main() { | |
runApp(App()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment