Recently made a small function, to make a global popover, can pop up anywhere, how to do this? Here’s the idea from start to finish:
- In the previous article, we wrote how to route forward without using context. Normally we would write this:
Navigator.of(context).pushNamed('new_page');
You have to pass a context. But sometimes we might want to jump if we can’t pass the context.
We can do this:
// Create a new navigatorKey
GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
// Then, find our MaterialApp
MaterialApp(
navigatorKey: navigatorKey,// Add this configuration
title: 'Flutter Demo',
theme: ThemeData.light(),
home: HomePage(),
)
Copy the code
Then we can redirect the page like this:
navigatorKey.currentState.pushNamed('new_page');
Ok, so we’ve got a contextless jump.
Anyway, now that we have this state, can we use the context inside? And I got excited to try it out:
showDialog(
context: navigatorKey.currentState.context,
builder: (context) => AlertDialog(
content: Text('content'),),)Copy the code
The result is very disappointed! Error:
Log: 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.
This context can only be used for routing. Why?
Looking at the call stack,
showDialog
->showGeneralDialog
->Navigator.of(context, rootNavigator: useRootNavigator).pushxxx
And finally here:
static NavigatorState of(
BuildContext context, {
bool rootNavigator = false.bool nullOk = false, {})final NavigatorState navigator = rootNavigator
? context.findRootAncestorStateOfType<NavigatorState>()
: context.findAncestorStateOfType<NavigatorState>();
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;
}
Copy the code
We see the wrong string, and then we pull out the core:
FindRootAncestorStateOfType < NavigatorState > and findAncestorStateOfType < NavigatorState >
If you’re already using Inheritedxxx, you’re familiar with this. We’re using Inheritedxxx to look up the root component object from the leaf node through the context, in this case finding the NavigatorState object.
But from the point of view of the corresponding implementation, the initial value of both methods is Element ancestor = _parent; If the parent context is the state context, the parent context cannot be found. So this simple way is not going to work.
But don’t despair, at least from this error, we can also see this from showGeneralDialog:
Navigator.of(context, rootNavigator: useRootNavigator).push<T>(_DialogRoute<T>(xxx
The dialog box is also a routing page, so we can make a copy of the source code. The idea is to push the dialogrouter by ourselves.
- Here is the second method, the floating layer:
Overlay
Overlay routine use, such as popupwindow, using the following method:
final overlay = Overlay.of(context);// Get an overlay
// Create an OverlayEntry
OverlayEntry entry = OverlayEntry(
builder: (context) {
return Material(
type: MaterialType.transparency,
child: Stack(
children: <Widget>[
Positioned(
top: 200,
left: 200,
child: GestureDetector(
onTap: () {
entry.remove();
entry = null;
},
child: Container(
color: Colors.redAccent
child: Text('hahaha'),
width: 100,
height: 100,),),),,,); });// Add it to display
overlay.insert(entry);
Copy the code
Okay, so after looking at this little demo, we see that pop-ups also need context. . Let’s try: final overlay = overlay of (navigatorKey. CurrentState. Context).
So when I run it, the overlay is empty and I can’t use it directly. Why is that?
The Overlay Widget is initialized in the Navigator build. The Overlay is the Navigator’s child.
After the previous dialog experience, the same problem can not be found here, because it is also from the navigator parent, definitely can not be found.
So how do you use Overlay? It’s not a route. You can’t push it.
To be honest, I had no idea, so I searched and searched
Bot_toast = bot_toast = bot_toast = bot_toast
Support all kinds of popboxes, toast, dialog boxes, notifications, cross-page support.
And then when I was done with it, I looked at the way he implemented it, which was the Overlay method, and I saw how he got the overlays.
The core is: Using the Overlay object in NavigatorState, I’m surprised there’s a method in navigator.
OverlayState get overlay => _overlaykey.currentState;
That is to say, we can obtain with just the navigatorKey overlay, access: navigatorKey. CurrentState. Overlay, well, with this overlay, we can always add floating layer.
I finished writing, above is the whole analysis and solution of this need, you can refer to the next ^_^.
Finally, we do the global popbox, there are two ways to choose, specific to see which needs to choose which it ~~