Flutter GetX更新区域设置正在重置GoRouter导航错误

xqnpmsa8  于 2023-05-23  发布在  Flutter
关注(0)|答案(2)|浏览(200)

bounty将在6天内到期。回答此问题可获得+150声望奖励。Chris希望引起更多关注这个问题。

我正在使用GoRouter进行导航,GetX用于多项功能,包括更新应用程序的locale
它正在更新语言,但问题是不知何故,我的导航堆栈正在被重置后调用。
为了更好地理解,我制作了一个Screenvideo,但你也可以自己测试here
我通过简单地调用来更新我的区域设置:

Locale locale = Locale(languageCode);
  await Get.updateLocale(locale);

我的路由看起来像这样:

final rootNavigatorKey = GlobalKey<NavigatorState>();

class AppRouter {
  static final _shellNavigatorKey = GlobalKey<NavigatorState>();

  static final router = GoRouter(
    initialLocation: IntroView.path,
    debugLogDiagnostics: true,
    navigatorKey: rootNavigatorKey,
    routes: [
      ShellRoute(
        navigatorKey: _shellNavigatorKey,
        pageBuilder: (context, state, child) {
          return NoTransitionPage(
            child: ScaffoldView(
              child: child,
            ),
          );
        },
        routes: [
          GoRoute(
            name: ProjectsView.name,
            path: '/projects',
            parentNavigatorKey: _shellNavigatorKey,
            pageBuilder: (context, state) {
              return const FadePageTransition(
                page: ProjectsView(),
              );
            },
            routes: [
              GoRoute(
                parentNavigatorKey: rootNavigatorKey,
                path: ':projectTitle',
                pageBuilder: (context, state) {
                  return FadePageTransition(
                    page: ProjectDetailScaffold(
                      project: Projects.values.byName(
                        state.params['projectTitle']!,
                      ),
                    ),
                  );
                },
              ),
            ],
          ),

我错过了什么?
让我知道如果你需要更多的信息!

u5i3ibmn

u5i3ibmn1#

现在我找到了一个不是很干净的解决方法,但它对我很有效:
在我调用await Get.updateLocale(locale);之后,我调用这个:

if (mounted) {
    while (context.canPop()) {
      context.pop();
    }
    context.pushReplacement('/projects/localizeIt');
  }

问题是GoRouter丢失了状态,因为updateLocale强制应用重新构建。作为解决方法,我弹出所有视图并转到调用updateLocale的位置。
就像我说的,这不是一个理想的解决方案。如果有人知道更好的解决方案,请告诉我。

q3aa0525

q3aa05252#

您当前的解决方案基本上涉及重新启动导航堆栈并在更改区域设置后重定向到特定页面,虽然这可能有效,但它似乎有点粗糙,可能会导致用户体验问题。
在Flutter中,语言环境的改变确实会导致小部件树的重建。但是,在此过程中清除导航堆栈似乎并不常见。通常,除非明确清除或修改,否则应在重新构建时维护导航堆栈。
该问题可能与GetXGoRouter如何相互作用有关。

  • GetX是一个状态管理解决方案,当语言环境改变时,它似乎会导致小部件树的完全重建。
  • 另一方面,GoRouter管理导航,并且应该在小部件树重建过程中维护其状态。

因此,您可以尝试并确保在每次重建时不会重新创建GoRouter示例。路由器应创建一次,并在应用程序的生命周期内进行维护。

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final router = AppRouter.router;

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerDelegate: router.routerDelegate,
      routeInformationParser: router.routeInformationParser,
    );
  }
}

并考虑将本地化和路由问题分开。
不直接调用Get.updateLocale,您可以创建一个单独的服务来 Package 此调用并保留导航状态。该服务可以监听区域设置更改并更新区域设置,而不会导致小部件树的完全重建。

class LocaleService extends GetxController {
  void updateLocale(String languageCode) async {
    Locale locale = Locale(languageCode);
    Get.updateLocale(locale);
    update();
  }
}

class LocaleSwitcher extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetBuilder<LocaleService>(
      init: LocaleService(),
      builder: (controller) {
        return DropdownButton<String>(
          value: Get.locale?.languageCode,
          items: <String>['en', 'fr', 'de'].map((String value) {
            return DropdownMenuItem<String>(
              value: value,
              child: Text(value),
            );
          }).toList(),
          onChanged: (newValue) {
            controller.updateLocale(newValue!);
          },
        );
      },
    );
  }
}

LocaleService是 Package Get.updateLocale调用的服务。
LocaleSwitcher是一个小部件,它使用GetBuilder来侦听LocaleService中的更改,并在区域设置更新时重新构建自己。
这样,当区域设置更改时,只重建LocaleSwitcher小部件,而不是整个小部件树。
或者:考虑使用GetMaterialApp,它将GetX与Flutter MaterialApp小部件集成(如图所示)。这可能有助于在更改区域设置时保留导航状态。
另见“What is the difference between GetMaterialApp of GetX and MaterialApp of Flutter?”。
这也意味着您将依赖GetX而不是GoRouter进行路由。如果你想坚持使用GoRouter进行路由,前两点就足够了。
但是,如果您可以过渡到GetX进行路由,请使用GetMaterialAp

相关问题