在Flutter应用中如何在没有上下文的情况下进行导航?

Ash*_*rma 10 flutter

我有一个应用程序可以使用OneSignal接收推送通知。我做了一个通知打开处理程序,应在单击通知时打开特定的屏幕。我如何导航到没有上下文的屏幕。或如何在应用启动时打开特定屏幕。我的代码:

OneSignal.shared.setNotificationOpenedHandler((notification) {
  var notify = notification.notification.payload.additionalData;
  if (notify["type"] == "message") {
    Navigator.of(context).push(
      MaterialPageRoute(
        builder: (context) => DM(user: notify['id']),
      ),
    );
  }
  if (notify["type"] == "user") {
    Navigator.of(context).push(
      MaterialPageRoute(
        builder: (context) => Profileo(notify["id"]),
      ),
    );
  }
  if (notify["type"] == "post") {
    Navigator.of(context).push(
      MaterialPageRoute(
        builder: (context) => ViewPost(notify["id"]),
      ),
    );
  }
});
Run Code Online (Sandbox Code Playgroud)

首次打开该应用程序时,我可以实现此目的,但是,即使我关闭了该应用程序,即使重新打开它也只能打开主页。我想那是因为上下文已更改。

请帮忙!!

y.s*_*gan 27

你可以使用这个很棒的插件:https : //pub.dev/packages/get

来自包的描述:一个一致的导航库,允许您在没有上下文的情况下从代码中的任何位置在屏幕之间导航、打开对话框和显示小吃栏。

Get.to(NextScreen()); // look at this simplicity :)
Get.back(); //  pop()
Get.off(NextScreen()); // clears the previous routes and opens a new screen.
Run Code Online (Sandbox Code Playgroud)

  • 投反对票,因为导入 GetX 来解决导航问题有点过分了。 (38认同)
  • 这个包太棒了!谢谢! (3认同)
  • 这个包绝对不精彩。它有许多错误,从其他库窃取的代码,并被其创建者抛弃。 (2认同)

小智 12

在这里看这个:https : //github.com/brianegan/flutter_redux/issues/5#issuecomment-361215074

您可以为导航设置全局键:

final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
Run Code Online (Sandbox Code Playgroud)

将其传递给MaterialApp:

new MaterialApp(
      title: 'MyApp',
      onGenerateRoute: generateRoute,
      navigatorKey: navigatorKey,
    );
Run Code Online (Sandbox Code Playgroud)

推送路线:

navigatorKey.currentState.pushNamed('/someRoute');
Run Code Online (Sandbox Code Playgroud)

  • @temirbek 在 main.dart 中定义 navigatorKey 并将其导入到其他文件中。 (5认同)
  • navigatorKey未定义 (2认同)
  • 另外,将MaterialApp的*navigatorKey*属性设置为声明的全局键(navigatorKey),而不是MaterialApp的*key*属性 (2认同)
  • @Mustafa 你能提供样品吗?我读过很多博客和论坛,都给出了相同的解决方案,但导航键可以从我的 dio 拦截器访问。 (2认同)
  • 我们使用 go router 来定义名称路由。这仍然有效吗? (2认同)

jos*_*oid 11

最快的修复方法是使用全局navigatorKey(如 @tsdevelopment 回答)。要修复 undefined navigatorKey,必须从实例化它的位置导入它(对于本例中的示例main.dart)。

你的main.dart

final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

void main() {
  runApp(CupertinoApp(
    title: 'Navigate without context',
    initialRoute: '/',
    navigatorKey: navigatorKey, // important
    onGenerateRoute: ...
  ));
}
Run Code Online (Sandbox Code Playgroud)

例如你在你的lib/utils/api.dart

import 'package:your_package_name/main.dart'; // important

abstract class API {
  static Future<dynamic> get() async {
     // call some api
     ...
     // then you want to navigate to specific screen like login
     navigatorKey.currentState?.pushNamed('/login'); // navigate to login, with null-aware check
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您喜欢服务方法,还可以提供一个要点示例。检查这个:https://gist.github.com/josephdicdican/81e59fad70530eac251ad6c28e2dcd4b


Yus*_*Amr 6

如果您想使用 globalKey 在没有上下文的情况下导航或显示对话框,尤其是使用 Bloc 或当您的逻辑与 UI 部分分离时,此解决方案是通用的。

首先安装这个包:

不:我使用的是空安全版本

  get_it: ^7.2.0
Run Code Online (Sandbox Code Playgroud)

然后为您的服务定位器创建一个单独的文件:

服务位置.dart

    import 'package:get_it/get_it.dart';
    
    GetIt locator = GetIt.instance;
    
    class NavigationService {
      final GlobalKey<NavigatorState> navigatorKey =
          new GlobalKey<NavigatorState>();
      Future<dynamic> navigateTo(String routeName) {
        return navigatorKey.currentState!.pushNamed(routeName);
      }
    
      void setupLocator() {
        locator.registerLazySingleton(() => NavigationService());
      }

  void showMyDialog() {
    showDialog(
        context: navigatorKey.currentContext!,
        builder: (context) => Center(
              child: Material(
                color: Colors.transparent,
                child: Text('Hello'),
              ),
            ));
  }
    }
Run Code Online (Sandbox Code Playgroud)

在 main.dart上

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  NavigationService().setupLocator();
  runApp(MyApp());
}
// add navigatorKey for MaterialApp

 MaterialApp(
        navigatorKey: locator<NavigationService>().navigatorKey,
      ),
Run Code Online (Sandbox Code Playgroud)

在您的业务逻辑文件bloc.dart中 ,在 bloc 类中或您想要在其中使用导航的任何类中定义它,然后开始在其中的任何函数中导航。

class Cubit extends Cubit<CubitState> {
  final NavigationService _navigationService = locator<NavigationService>();
  void sampleFunction(){
       _navigationService.navigateTo('/home_screen'); // to navigate
       _navigationService.showMyDialog(); // to show dialog

    }
}
Run Code Online (Sandbox Code Playgroud)

不是:我使用generateRoute 进行路由。

  • get_it 不是 getx (6认同)