In flutter, we often use such code
// open a new page Navigator.of (context) .push // open Scaffold of Drawer Scaffold.of (context) .openDrawer // get display1 style text theme Theme.of (context) .textTheme.display1
Well, this of (context) in the end is what is it. We are here to open a new Navigator page, for example.
static NavigatorState of ( BuildContext context, { BOOL rootNavigator = to false , BOOL nullok = to false , }) { // critical code ------------------------- V ---------------- Final NavigatorState Navigator = rootNavigator context.rootAncestorStateOfType (? const TypeMatcher <NavigatorState> ()) : context.ancestorStateOfType ( const TypeMatcher <NavigatorState> ()
); / / critical code ^ ---------------------------------------- Assert (() { IF (Navigator == null && !nullOk) { throw FlutterError( 'Navigator operation requested with a context that does not include a Navigator.\n' 'The context used to push or pop routes from the Navigator must be that of a ' 'widget that is a descendant of a Navigator widget.' ); } return true; }()); return navigator; }
We can see, the key code section traversing the Element tree by context.rootAncestorStateOfType up, and find the nearest match NavigatorState. That is actually context of inter-component obtains a data package.
Our Navigator of the operation is to push through NavigatorState found to complete.
Not only that, BuildContext there are many ways to get across the Component Object
ancestorInheritedElementForWidgetOfExactType(Type targetType) → InheritedElement ancestorRenderObjectOfType(TypeMatcher matcher) → RenderObject ancestorStateOfType(TypeMatcher matcher) → State ancestorWidgetOfExactType(Type targetType) → Widget findRenderObject() → RenderObject inheritFromElement(InheritedElement ancestor, { Object aspect }) → InheritedWidget inheritFromWidgetOfExactType(Type targetType, { Object aspect }) → InheritedWidget rootAncestorStateOfType(TypeMatcher matcher) → State visitAncestorElements(bool visitor(Element element)) → void visitChildElements(ElementVisitor visitor) → void
Note that, in the State in initState stage is unable to take the cross-component data, these methods can be used only after didChangeDependencies.
Recalling the problems
we now look at the encounter before the current context Navigator does not contain this problem is not very simple to do.
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: FlatButton( onPressed: () { Navigator.of(context).push( MaterialPageRoute(builder: (context) => SecondPage())); }, child: Text('跳转')), ), ), ); } }
When we use Navigator.of (context) in the build function in this context is actually created by MyApp this widget out of the Element object, and the method of looking up when the ancestor node (MyApp ancestor node) does not exist MaterialApp , there is no Navigator it provides.
So when we put Scaffold part split into another widget, we FirstPage in the build function, access to the BuildContext FirstPage, and then looking up found MaterialApp, and find Navigator it provides, so he can be happy page jump a.