简体   繁体   English

在 flutter 中导航,无需上下文

[英]Navigation in flutter without context

I created a service folder and made a file in it called request.我创建了一个服务文件夹并在其中创建了一个名为 request.xml 的文件。 dart, here I intend to place all requests I make into a class called AuthService, with the login request below I want to be able to navigate to the home screen once response.statusCode == 200 or 201 but I am unable to do that because navigation requires a context and my class is neither a Stateful nor Stateless widget, is there any way I can navigate without the context?? dart,在这里我打算将我发出的所有请求放入名为 AuthService 的 class 中,下面的登录请求我希望能够在 response.statusCode == 200 或 201 后导航到主屏幕,但我无法这样做,因为导航需要上下文,而我的 class 既不是有状态也不是无状态小部件,有没有什么方法可以在没有上下文的情况下导航?

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/material.dart';

class AuthService {

  login(email, password) async {
    SharedPreferences sharedPreferences = await SharedPreferences.getInstance();

    if (email == "" && password == "") {
      return;
    }

    try {
      Map data = {'email': email, 'password': password};

      var jsonResponse;
      var response = await http
          .post('https://imyLink.com/authenticate', body: data);
      if (response.statusCode == 200 || response.statusCode == 201) {

//I want to navigate to my home screen once the request made is successful

        jsonResponse = json.decode(response.body);
        if (jsonResponse != null) {
          await sharedPreferences.setString("userToken", jsonResponse["token"]);
          var token = sharedPreferences.getString("userToken");
          print('Token: $token');
          print(jsonResponse);
          print("Login successful");
        }
      } else {
        print(response.statusCode);
        print('Login Unsuccessful');
        print(response.body);
      }
    } catch (e) {
      print(e);
    }
}

First, create a class首先,创建一个 class

import 'package:flutter/material.dart';

class NavigationService{
  GlobalKey<NavigatorState> navigationKey;

  static NavigationService instance = NavigationService();

   NavigationService(){
     navigationKey = GlobalKey<NavigatorState>();
   }

  Future<dynamic> navigateToReplacement(String _rn){
return navigationKey.currentState.pushReplacementNamed(_rn);
  }
 Future<dynamic> navigateTo(String _rn){
   return navigationKey.currentState.pushNamed(_rn);
  }
 Future<dynamic> navigateToRoute(MaterialPageRoute _rn){
   return navigationKey.currentState.push(_rn);
  }

 goback(){
   return navigationKey.currentState.pop();

  }
  }

In your main.dart file.在您的 main.dart 文件中。

 MaterialApp(
  navigatorKey: NavigationService.instance.navigationKey,
  initialRoute: "login",
  routes: {
    "login":(BuildContext context) =>Login(),
    "register":(BuildContext context) =>Register(),
    "home":(BuildContext context) => Home(),

  },
);

Then you can call the function from anywhere in your project like...然后,您可以从项目中的任何位置调用 function,例如...

 NavigationService.instance.navigateToReplacement("home");
 NavigationService.instance.navigateTo("home");

OPTION 1选项1

If you will be calling the login method in either a Stateful or Stateless widget.如果您将在有StatefulStateless小部件中调用login方法。 You can pass context as a parameter to the login method of your AuthService class.您可以将context作为参数传递给AuthService class 的login方法。

I added a demo using your code as an example:我以您的代码为例添加了一个演示:

class AuthService {

  // pass context as a parameter
  login(email, password, context) async {
    SharedPreferences sharedPreferences = await SharedPreferences.getInstance();

    if (email == "" && password == "") {
      return;
    }

    try {
      Map data = {'email': email, 'password': password};

      var jsonResponse;
      var response = await http
          .post('https://imyLink.com/authenticate', body: data);
      if (response.statusCode == 200 || response.statusCode == 201) {

      //I want to navigate to my home screen once the request made is successful
      Navigator.of(context).push(YOUR_ROUTE); // new line

        jsonResponse = json.decode(response.body);
        if (jsonResponse != null) {
          await sharedPreferences.setString("userToken", jsonResponse["token"]);
          var token = sharedPreferences.getString("userToken");
          print('Token: $token');
          print(jsonResponse);
          print("Login successful");
        }
      } else {
        print(response.statusCode);
        print('Login Unsuccessful');
        print(response.body);
      }
    } catch (e) {
      print(e);
    }
}

OPTION 2选项 2

You can access your app's Navigator without a context by setting the navigatorKey property of your MaterialApp:通过设置 MaterialApp 的 navigatorKey 属性,您可以在没有上下文的情况下访问应用的导航器:

  /// A key to use when building the [Navigator].
  ///
  /// If a [navigatorKey] is specified, the [Navigator] can be directly
  /// manipulated without first obtaining it from a [BuildContext] via
  /// [Navigator.of]: from the [navigatorKey], use the [GlobalKey.currentState]
  /// getter.
  ///
  /// If this is changed, a new [Navigator] will be created, losing all the
  /// application state in the process; in that case, the [navigatorObservers]
  /// must also be changed, since the previous observers will be attached to the
  /// previous navigator.
  final GlobalKey<NavigatorState> navigatorKey;

Create the key:创建密钥:

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

Pass it to MaterialApp:将其传递给 MaterialApp:

new MaterialApp(
      title: 'MyApp',
      navigatorKey: key,
    );

Push routes (both named and non-named routes work):推送路由(命名和非命名路由都有效):

navigatorKey.currentState.pushNamed('/someRoute');

Find more details about option 2 by following the github issue below: https://github.com/brianegan/flutter_redux/issues/5#issuecomment-361215074按照下面的 github 问题查找有关选项 2 的更多详细信息: https://github.com/brianegan/flutter_redux/issues/5#issuecomment-361215074

You can use flutter Get package.您可以使用 flutter Get package。

Here is link .这是链接

you can use this plugin to skip the required context您可以使用此插件跳过所需的上下文

https://pub.dev/packages/one_context https://pub.dev/packages/one_context

// go to second page using named route
OneContext().pushNamed('/second');
// go to second page using MaterialPageRoute
OneContext().push(MaterialPageRoute(builder: (_) => SecondPage()));
// go back from second page
OneContext().pop();

Is there a way to use S.R Keshav method to access pages and giving them an argument?有没有办法使用 S.R Keshav 方法访问页面并给它们一个参数?

routes: {
 "sce": (BuildContext context, {args}) => MatchConversation(args as int),
 "passport": (BuildContext context, {dynamic args}) => Passport(),
},

It looks that the arg is lost when Navigator goes in _pushEntry method.当 Navigator 进入 _pushEntry 方法时,看起来 arg 丢失了。 The navigated Page is accessed, but no initial arguments are loaded.访问导航页面,但未加载初始 arguments。

Simple and clean solution without any plugin/package.没有任何插件/包的简单而干净的解决方案。

  1. Create global variable:创建全局变量:

     final GlobalKey<NavigatorState> navKey = GlobalKey<NavigatorState>();
  2. Add this global key to the MaterialApp:将此全局键添加到 MaterialApp:

     child: MaterialApp( title: 'MyApp', navigatorKey: navKey, ));
  3. Now you have 2 ways to use it.现在您有两种使用方法。 Either define routes and use route names or use non-named route (this is the only way if you do not want to use global variables and pass parameters directly to a widget).定义路由并使用路由名称或使用非命名路由(如果您不想使用全局变量并将参数直接传递给小部件,这是唯一的方法)。

a) Option 1. Define routes and then use route names: a) 选项 1. 定义路线,然后使用路线名称:

// Define route names
MaterialApp(
      title: 'MyApp',
      navigatorKey: navKey,
routes: {
            "login": (BuildContext context) => LoginPage(),
            "register": (BuildContext context) => RegisterPage(),

    );

// Now anywhere inside your code change widget like this without context:
navKey.currentState?.pushNamed('login');

b) Option 2. Push non-named routes to the navigator: b) 选项 2. 将未命名的路由推送到导航器:

navKey.currentState?.push(MaterialPageRoute(builder: (_) => LoginPage()));

This way allows to pass parameters directly to widget without global variable:这种方式允许在没有全局变量的情况下直接将参数传递给小部件:

navKey.currentState?.push(MaterialPageRoute(builder: (_) => HomePage('yourStringValue', 32)));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM