簡體   English   中英

在 Flutter 中,Getx 包 unknownRoute 不起作用

[英]In Flutter, Getx package unknownRoute not working

我開始在顫振中學習 Getx,並使用導航。

我想設置unknownRoute,以防namedroute中有錯字等,因此應用程序應該轉到默認頁面。

我喜歡這樣:

 return GetMaterialApp(
        title: 'Named navigation',
        unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),
        initialRoute: '/', // this defines with route will be opened first

        getPages: [
          GetPage(name: '/', page: () => MyNavigationNamed()),
          GetPage(name: '/second', page: () => SecondScreenNamed()),
          GetPage(name: '/third', page: () => ThirdParametersScreenNamed()),
          GetPage(
              name: '/third_with_built_param/:someValue',
              page: () => ThirdParametersScreenNamed()),
        ],

我有小部件:

class UnknownRoutePage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Container(child: Text('UNKNOWN ROUTE')));
  }

}

但是,當我嘗試通過在路由名稱中出錯來測試它時,如下所示:

 ElevatedButton(
                  onPressed: () {
                    Get.toNamed(
                      '/s');     //THIS IS A DUMMY INCORRECT NAME TO TESTING
                  },
                  child: Text('Error in route name, goes to defalt set above.'),
                ),

我希望我的 UnknownRoutePage() 能夠打開。

但是我收到此消息:

The following assertion was thrown building Directionality(textDirection: ltr):
'package:flutter/src/widgets/framework.dart': Failed assertion: line 5033 pos 14: '_dependents.isEmpty': is not true.


Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=2_bug.md

The relevant error-causing widget was: 
  Directionality file:///Users/reuvenberman/Developer/flutter/.pub-cache/hosted/pub.dartlang.org/get-4.3.8/lib/get_navigation/src/root/get_material_app.dart:217:12
When the exception was thrown, this was the stack: 
#2      InheritedElement.debugDeactivated.<anonymous closure> (package:flutter/src/widgets/framework.dart:5033:14)
#3      InheritedElement.debugDeactivated (package:flutter/src/widgets/framework.dart:5035:6)
#4      _InactiveElements._deactivateRecursively.<anonymous closure> (package:flutter/src/widgets/framework.dart:1869:15)
#5      _InactiveElements._deactivateRecursively (package:flutter/src/widgets/framework.dart:1871:6)
#6      ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:4628:14)
...
====================================================================================================

======== Exception caught by widgets library =======================================================
The following assertion was thrown while finalizing the widget tree:
Duplicate GlobalKey detected in widget tree.

The following GlobalKey was specified multiple times in the widget tree. This will lead to parts of the widget tree being truncated unexpectedly, because the second time a key is seen, the previous instance is moved to the new location. The key was:
- [LabeledGlobalKey<NavigatorState>#56deb Key Created by default]
This was determined by noticing that after the widget with the above global key was moved out of its previous parent, that previous parent never updated during this frame, meaning that it either did not update at all or updated before the widget was moved, in either case implying that it still thinks that it should have a child with that global key.
The specific parent that did not update after having one or more children forcibly removed due to GlobalKey reparenting is:
- Directionality(textDirection: ltr)
A GlobalKey can only be specified on one widget at a time in the widget tree.
When the exception was thrown, this was the stack: 
#0      BuildOwner.finalizeTree.<anonymous closure> (package:flutter/src/widgets/framework.dart:2900:15)
#1      BuildOwner.finalizeTree (package:flutter/src/widgets/framework.dart:2925:8)
#2      WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:877:19)
#3      RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:328:5)
#4      SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1144:15)
...

為什么這不起作用?

謝謝

我面臨同樣的問題,也找不到有關該主題的任何信息。 在做了一些測試並查看了實際的包代碼之后,我得出的結論是 GetX 只關心它是否可以匹配 URI 開頭的路由。 因此,如果您有“/”的路由,那么“/”之后的任何內容(例如“/non-existent-route/1/2/3/”)仍將匹配“/”,因為它以“/”開頭。 同樣,如果你有一個像“/admin-area”這樣的路由,另一個是“/admin-area/home”,那么“/admin-area/non-existent-route/1/2/3/”仍然會匹配到"/admin-area" 和類似 "/admin-area/home/non-existent-route/1/2/3/" 的 URI 仍將與 "/admin-area/home" 匹配。 由於這不是 web 的預期行為,當使用 currentRoute 在導航中突出顯示當前頁面時可能會導致問題,並且考慮到 GetX 的文檔非常差,我只能假設這是一個錯誤。

我可以正確解決此問題的唯一方法是根本不使用 GetMaterialApp getPages 屬性,而是使用 onGenerateRoute 。 Get.toNamed 仍然有效,路由器只會路由到完全匹配,如下所示:

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      initialRoute: "/",
      onGenerateRoute: (RouteSettings route) {
        var uri = Uri.parse(route.name!);
        switch (uri.path) {
          case "/":
            return MaterialPageRoute(
              settings: route,
              builder: (context) => const RootPage(),
            );
          default:
            return MaterialPageRoute(
              settings: route,
              builder: (context) => const UnkownPage(),
            );
        }
      },
    );
  }

如果您願意,您還可以像這樣將此邏輯移出 GetMaterialApp:

@override
Widget build(BuildContext context) {
  return GetMaterialApp(
    initialRoute: "/",
    onGenerateRoute: generateRoutes
    },
  );
}

//another file
Route<dynamic> generateRoutes(RouteSettings route) {
  var uri = Uri.parse(route.name!);
  switch (uri.path) {
    case "/":
      return MaterialPageRoute(
        settings: route,
        builder: (context) => const UnimplementedPage('Unkown'),
      );
    default:
      return MaterialPageRoute(
        settings: route,
        builder: (context) => const UnimplementedPage('Unkown'),
      );
  }
}

我遇到了同樣的問題,但我深入研究了 Get 代碼,發現有一個matchRoute()方法將為 unknownRoute 返回“/”。

--> 總之,要讓unknownRoute工作,你的初始路由不能是“/”,它可以是其他任何東西,例如“/home”、“/main”、“/init”,但它只是可以' t 是“/”。


我為它創建了一個 PR: https ://github.com/jonataslaw/getx/pull/2256

我遇到了類似的問題,但沒有收到任何錯誤消息。 相反,當我試圖導航到一個不存在的頁面時,我總是在起始頁面上結束。 我沒有找到任何澄清。

我的解決方案是為 initialRoute 設置更重要的內容,例如:initialRoute: '/beginpage'。 '/' 和 '/start' 對我不起作用,也許它們是一些保留路線。 我在您的代碼中看到了同樣的問題,請嘗試更改它。

如果這沒有幫助,您可以查看我在 github 上找到的現成示例,它幫助我確定了我的問題: https ://github.com/ducafecat/getx_quick_start。

我找到了一種簡單的方法,您可以跳過“getPage:”中的主頁,因為實現了“initialRoute:”。

return GetMaterialApp(
    title: 'Named navigation',
    unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),
    initialRoute: '/',

    getPages: [

      GetPage(name: '/second', page: () => SecondScreenNamed()),
      GetPage(name: '/third', page: () => ThirdParametersScreenNamed()),
      GetPage(
          name: '/third_with_built_param/:someValue',
          page: () => ThirdParametersScreenNamed()),
    ],

試試看。

我解決了

notWorking 未知路由

第一個AppInformationParser放入GetMaterialApp.router

routeInformationParser: AppInformationParser()

   return GetMaterialApp.router(
      title: 'ACRI',
      debugShowCheckedModeBanner: false,
      theme: AppTheme.appTheme,
      themeMode: ThemeMode.light,
      locale: Get.locale ?? const Locale('tr'),
      translations: AppLocalization(),
      routerDelegate: Get.createDelegate(
        backButtonPopMode: PopMode.Page,
        notFoundRoute: AppPages.pageNotFound,
      ),
      localizationsDelegates: AppLocalizationDelegate.appDelegates,
      supportedLocales: AppLocalizationDelegate.supportedLocales,
      routeInformationParser: AppInformationParser(),
      backButtonDispatcher: AppBackButtonDispatcher(),
      getPages: AppPages.pages,
      initialBinding: AccountBinding(),
      unknownRoute: AppPages.pageNotFound,
    );

並創建AppInformationParser

  class AppInformationParser extends RouteInformationParser<GetNavConfig> {
  /// [initialRoute] => [/]
  AppInformationParser({
    String? initialRoute,
  })  : initialRoute = initialRoute ?? '/',
        super();

  /// Initial route
  /// default '/'
  final String initialRoute;

  @override
  Future<GetNavConfig> parseRouteInformation(
    RouteInformation routeInformation,
  ) {
    String? location = routeInformation.location; // => [/]
    if (location == '/') {
      if (!Get.routeTree.routes.any((e) => e.name == '/')) {
        location = initialRoute;
      }
    }

    // if (!Get.routeTree.routes.any((e) => false)) {
    //   location = AppRoutes.notFound;
    // }

    final matchResult = Get.routeTree.matchRoute(location ?? initialRoute);
    String? matchResultLocation = matchResult.route?.name;

    log("App Information Parser location : $location");
    log("Match Result Parser location : ${matchResult.route?.name}");

    if (matchResultLocation != location) {
      location = AppRoutes.notFound;
    } else if (matchResultLocation == AppRoutes.navigation) {
      location = AppRoutes.home;
    } else if (matchResultLocation == AppRoutes.list) {
      location = AppRoutes.vehicles;
    } else if (matchResultLocation == AppRoutes.report) {
      location = AppRoutes.vehicleReport;
    } else if (matchResultLocation == AppRoutes.map) {
      location = AppRoutes.mapVehicles;
    }

    final result = Get.routeTree.matchRoute(location ?? initialRoute);

    return SynchronousFuture(
      GetNavConfig(
        currentTreeBranch: result.treeBranch,
        location: location,
        state: routeInformation.state,
      ),
    );
  }

  @override
  RouteInformation? restoreRouteInformation(GetNavConfig configuration) {
    return RouteInformation(
      location: configuration.location,
      state: configuration.state,
    );
  }
}

這會給你輸入的路由器名稱

 final matchResult = Get.routeTree.matchRoute(location ?? initialRoute);
 String? matchResultLocation = matchResult.route?.name;

並比較您的location路由器

   if (matchResultLocation != location) {
      location = AppRoutes.notFound;
    }

如果matchResultLocation不比較location ,則它是未知路由器。

最后為GetNavConfig添加了matchRoute方法並解決UnknownRoute

    final result = Get.routeTree.matchRoute(location ?? initialRoute);

    return SynchronousFuture(
      GetNavConfig(
        currentTreeBranch: result.treeBranch,
        location: location,
        state: routeInformation.state,
      ),
    );

已解決:首先我使用了 GetMaterialApp 中的 getPages 屬性:

    return GetMaterialApp(
      localizationsDelegates: context.localizationDelegates,
      supportedLocales: context.supportedLocales,
      locale: context.locale,
      debugShowCheckedModeBanner: false,
      title: Constants.appName,
      //Rutas fluro
      // onGenerateRoute: Flurorouter.router.generator,
      // onGenerateRoute: (RouteSettings route){
      //   var uri = Uri.parse(route.name!);
      //   switch (uri.path) {
      //     case "/":
      //       return GetMaterialPageView(
      //         settings: route,
      //         builder: (context) => const RootPage(),
      //       );
      //     default:
      //       return MaterialPageRoute(
      //         settings: route,
      //         builder: (context) => const UnkownPage(),
      //       );
      //   }  
      // },
      initialBinding: InitialBindings(),
      initialRoute: AppRoutes.initialRoute,
      getPages: AppPages.pages,
      unknownRoute: GetPage(name: '/notfound', page: () => const Screen404()),
      // routes: AppRoutes.getAppRoutes(),
      theme: AppTheme.lightTheme,
    );

在 AppPages.Pages 里面我有我項目的所有頁面,每個頁面看起來像這樣:

    GetPage(
      name: AppRoutes.SPLASH,
      page: () => AppRoutes.routes.contains(Get.currentRoute)
        ?SplashScreen()
        :const Screen404(),
    ),

在返回頁面之前,我在頁面屬性上使用此驗證來返回當前路由並驗證路由是否與我在 AppRoutes 上定義的相同,如果不一樣,我會返回屏幕 404。

如果路由有這樣的參數:

    GetPage(  
      name: "${AppRoutes.CANCEL_RESERVATION}/:id_reservation",
      page: (){
        //TODO VERIFICAR QUE ID EXISTA EN LISTADO DE AMENIDADES
        print(Get.parameters);
        print(Get.currentRoute);
        final id = int.tryParse(Get.parameters['id_reservation']!);
        final controller = Get.find<MyReservationsController>();
        controller.getReservationSelectedToCancel(id);
        if(controller.myReservationToCanel != null){
          return CancelReservationScreen(
            reservation: id,
          ); 
        }else{
          return const Screen404();
        }
      },
      binding: MyReservationsBinding(),
    ),

這樣我們也可以使用綁定。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM