问题
I'm trying to create a BlocListener
that has the ability to listen to all pages/routes throughout the app just like how you can access a Bloc
or a Provider
all throughout the app if they are defined at root-level like in the code below
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<IdentityTokenProvider>(
create: (_) => IdentityTokenProvider(),
),
],
child: MultiBlocProvider(
providers: [
BlocProvider<AuthBloc>(
create: (_) => AuthBloc(),
),
],
child: MaterialApp(
debugShowCheckedModeBanner: AppConfig.DEBUGGABLE,
theme: ThemeData(
// fontFamily: CustomFontStyle.montserrat,
),
home: AuthListener(
child: Center(
child: const MainApp(),
),
),
),
),
),
);
As you can see, I have providers, blocs, and one listener. I have no problem accessing the blocs and providers in other pages. My problem is the auth listener. I lose access to the AuthListener
once I move to a different page (by removing stack) , because it is inside the MaterialApp
. However, in this instance, I need that specific listener (AuthListener
) to be inside a MaterialApp
, because it consists of code that uses page navigations (which doesn't work if the implementation is done outside/above the widget tree of a MaterialApp
), and makes us of the MaterialApp
context for showing dialogs.
My implementation of page routing which removes the stack, which is another cause of losing access to the AuthListener
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => route),
(Route<dynamic> route) => false);
Why do I remove the route/page stack when moving to a different page?
- I specifically use this after authentication. You don't really want a user to be able to press back button after logging in, andredirect the user back to the login page right? Usually back button should hide/close the app when they are logged in.
My AuthListener
implementation
class AuthListener extends StatefulWidget {
final Widget child;
const AuthListener({Key key, @required this.child}) : super(key: key);
@override
_AuthListenerState createState() => _AuthListenerState();
}
class _AuthListenerState extends State<AuthListener> {
@override
Widget build(BuildContext context) {
return BlocListener<AuthBloc, AuthState>(
listener: (context, state) {
if (state is AuthAuthenticated) {
PageRouterController.pushAndRemoveStack(context, const EcomPage());
} else if (state is AuthUnauthenticated) {
PageRouterController.pushAndRemoveStack(context, const LoginPage());
}
},
child: widget.child,
);
}
}
Is there a different way around this?
回答1:
So I ended up defining a
static final GlobalKey<NavigatorState> navigatorKey = new GlobalKey();
and used it in my MaterialApp
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: App.DEBUGGABLE,
theme: ThemeData(
// fontFamily: CustomFontStyle.montserrat,
),
navigatorKey: App.navigatorKey,
home: Center(
child: const LoginPage(),
),
);
}
So then, whenever I have to navigate in cases where the implementation is outside the MaterialApp (in my case via the AuthListener which is found at root-level, above the MaterialApp), I can navigate via
App.navigatorKey.currentState.pushAndRemoveUntil(
MaterialPageRoute(builder: (_) => route),
(Route<dynamic> route) => false);
Which means I can finally have access to the MaterialApp navigator and context even with the listener outside the MaterialApp which allows me to do both navigation and showing of dialogs
来源:https://stackoverflow.com/questions/61295539/how-to-create-a-bloclistener-that-can-listen-to-all-pages-in-flutter-with-access