我在项目中使用go_router。我有一个单独的文件,其中包含一个包含所有路由(主页、登录、注册)的 GoRouter 实例。然后,我用肘加了认证。因此,我必须将我的 GoRouter 实例修改为通过 auth cubit 接收的函数,并使用它重定向到适当的路由。
一切看起来都很好,但后来我意识到了一些事情。例如,如果我在登录路径中并将寄存器推送到堆栈并修改寄存器页面并保存文件,则热重载将使我返回登录。所以每次我想对注册页面进行一些更改时,我都会返回登录路径,然后手动返回注册页面查看我的更改。
这是一个例子:
PS:我刚刚开始使用 go_router 包,所以也许我做错了什么。
解决办法很简单
GoRouter 存储您的路线状态。如果您创建 GoRouter 的新实例,那么它会丢失状态并导航到初始路线。
为了解决这个问题,我创建了 GoRouter 的实例并将其存储为单例或全局实例。
class AuthNavigation {
static const String settings = '/';
static const String myFriends = '/my_friends';
final GoRouter goRouter; // This instance will be store route state
AuthNavigation() : goRouter = _router;
static GoRouter get _router => GoRouter(
routes: <GoRoute>[...],
);
}
只需将您的路由器标记为static,以便每次在MaterialApp.router()
中初始化它时它都使用相同的实例class AppRouter {
static final GoRouter _router = GoRouter(
routes: [
GoRoute(
path: "/",
builder: (context, state) => const HomeScreen(),
),
],
);
GoRouter get router => _router;
}
并且,在 MaterialApp.router() 中:
MaterialApp.router(
routerDelegate: AppRouter().router.routerDelegate,
routeInformationProvider: AppRouter().router.routeInformationProvider,
routeInformationParser: AppRouter().router.routeInformationParser,
)
您应该将创建的路由类定义为最终的并将其交给Material App。这对我有用。 最终 _appRouter = NavigatorRoutes(); 路由器配置:_appRouter.router,
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
await EasyLocalization.ensureInitialized();
runApp(EasyLocalization(
supportedLocales: LocalizationsConfig.supportedLocales,
path: LocalizationsConfig.path,
child: App(),
));
}
class App extends StatelessWidget {
App({super.key});
final _appRouter = NavigatorRoutes();
final _providers = Providers();
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: _providers.items,
child: MaterialApp.router(
debugShowCheckedModeBanner: false,
title: 'Map Mates',
theme: AppTheme.baseScheme,
routerConfig: _appRouter.router,
),
);
}
}
我的 NavigatorRoutes 类是这样的
part of 'app_config.dart';
class NavigatorRoutes {
final GoRouter router = GoRouter(
errorBuilder: (BuildContext context, GoRouterState state) => const NotFoundPage(),
initialLocation: RouteName.root.path,
routes: <RouteBase>[
GoRoute(
path: RouteName.root.path,
builder: (BuildContext context, GoRouterState state) {
return const Root();
},
routes: <RouteBase>[
GoRoute(
path: RouteName.mapScreen.routeName,
builder: (BuildContext context, GoRouterState state) {
return const MapBasePage();
},
),
GoRoute(
path: RouteName.loginScreen.routeName,
builder: (BuildContext context, GoRouterState state) {
return const LoginPage();
},
),
GoRoute(
path: RouteName.singInScreen.routeName,
builder: (BuildContext context, GoRouterState state) {
return const SingInPage();
},
),
GoRoute(
path: RouteName.frogPassPage.routeName,
builder: (BuildContext context, GoRouterState state) {
return const FrogPassPage();
},
),
GoRoute(
path: RouteName.homePage.routeName,
builder: (BuildContext context, GoRouterState state) {
return const HomePage();
},
),
GoRoute(
path: RouteName.editProfilePage.routeName,
builder: (BuildContext context, GoRouterState state) {
return const EditProfilePage();
},
),
],
),
GoRoute(
path: RouteName.camera.path,
builder: (BuildContext context, GoRouterState state) {
return const CameraPage();
},
),
GoRoute(
path: RouteName.playerPage.path,
builder: (BuildContext context, GoRouterState state) {
var data = state.extra as Map<String, dynamic>;
return EditContentPage(
imageFile: data['imageFile'],
videoFile: data["videoFile"],
);
},
),
],
);
}
我已经制定了一个可行的解决方法。 您可以使用示例代码查看模板存储库。
它由 Splash、OnBoarding、SignIn 和带有导航栏和子页面的主页组成。
还可以将 redirect 与 AuthState ChangeNotifier 一起使用。
https://github.com/Christer-Muntean/go_router_with_navbar
您可以在此处查看应用程序视频预览: https://www.utvikler.app/post/spar-tid-og-ressurser-effektiv-navigering-i-flutter-med-go_router-utforsk-v% C3%A5rt-github-repo
尝试像这样实现:
class MyApp extends ConsumerWidget {
MyApp({Key? key}) : super(key: key);
late final appRoutes = AppRoutes();
@override
Widget build(BuildContext context, WidgetRef ref) {
final ThemeModeState currentTheme = ref.watch(themeProvider);
return MaterialApp.router(
title: 'Starmie',
debugShowCheckedModeBanner: false,
theme: lightTheme,
darkTheme: darkTheme,
themeMode: currentTheme.themeMode,
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
routeInformationParser: appRoutes.goRouter.routeInformationParser,
routerDelegate: appRoutes.goRouter.routerDelegate,
routeInformationProvider: appRoutes.goRouter.routeInformationProvider,
);
}
}
通过以下代码即可实现想要的输出。
///this class contaqins list of go router which will be use in the app
class AppRoute {
// using a factory is important
// because it promises to return _an_ object of this type
// but it doesn't promise to make a new one.
///return the instance of the
factory AppRoute() => _instance;
AppRoute._internal() {
// initialization logic
}
// This named constructor is the "real" constructor
// It'll be called exactly once, by the static property assignment above
// it's also private, so it can only be called in this class
static final AppRoute _instance = AppRoute._internal();
static final GoRouter _router = GoRouter(
navigatorKey: _rootNavigatorKey,
routes: routeBase,
errorBuilder: (BuildContext context, GoRouterState state) =>
const NotFound(),
);
///list of route base for the router
static List<RouteBase> routeBase = <RouteBase>[
GoRoute(
path: '/',
builder: (BuildContext context, GoRouterState state) =>
const SpalshScreen(),
),
GoRoute(
path: AppRoutes.internalError,
builder: (BuildContext context, GoRouterState state) =>
const InternalError()),
];
///retrun router object with initial location
static GoRouter getRoute(String initialLocation) => GoRouter(
navigatorKey: _rootNavigatorKey,
routes: routeBase,
initialLocation: initialLocation,
errorBuilder: (BuildContext context, GoRouterState state) =>
const NotFound(),
);
///return router object
static GoRouter get router => _router;
}
///this class hold the custom routes name that will be use in the app
class AppRoutes {
///return routename ='internal-error'
static String internalError = '/internal-error';
}
如果其他人仍然遇到问题,那么这里是解决方案
main.dart
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: klightTheme,
useMaterial3: true,
),
darkTheme: ThemeData(
colorScheme: kdarkTheme,
useMaterial3: true,
),
routerConfig: MyRoute.routes,
);
}
}
routes.dart
class MyRoute {
// here was the problem in my case i wasn't using the static property and this cause the the page reload to the initial route.
static final GoRouter routes = GoRouter(
initialLocation: '/',
routes: [
GoRoute(
path: '/',
name: WelcomeScreen.id,
builder: (context, state) {
return const WelcomeScreen(title: 'Hello World');
},
),
GoRoute(
path: '/${LoginScreen.id}',
name: LoginScreen.id,
builder: (context, state) {
return const LoginScreen();
},
),
GoRoute(
path: '/${RegisterScreen.id}',
name: RegisterScreen.id,
builder: (context, state) {
return const RegisterScreen();
},
),
GoRoute(
path: '/${ChatScreen.id}',
name: ChatScreen.id,
builder: (context, state) {
return const ChatScreen();
},
),
],
);
}