flutter:根据不同的状态路由到不同的页面

Posted

技术标签:

【中文标题】flutter:根据不同的状态路由到不同的页面【英文标题】:flutter: route into different pages according to different status 【发布时间】:2018-08-27 19:41:48 【问题描述】:

尝试根据我的应用程序中的用户状态(是否登录)进行重定向,但由于我不确定如何在方法中获取 BuildContext,因此无法正常工作。

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:t2/helpers/currentuser.dart';

import 'screens/dashboard.dart';
import 'screens/login.dart';

void main() => runApp(new MyApp());

CurrentUser user = new CurrentUser();

Future checkActiveUser() async 
  SharedPreferences prefs = await SharedPreferences.getInstance();

  user.usr = prefs.get('usr');
  user.pwd = prefs.get('pwd');
  if (user.usr.length == 0 && user.pwd.length == 0) 
    user.isLoggedIn = false;
    Navigator.of(x).pushNamedAndRemoveUntil('/dashboard', (Route<dynamic> route) => false);
   else 
    // Send to login screen
    user.isLoggedIn = false;
    Navigator.of(x).pushNamedAndRemoveUntil('/login', (Route<dynamic> route) => false);
  

  return user.isLoggedIn;

  /*
// How to read/write to local storage
int counter = (prefs.getInt('counter') ?? 0) + 1;
print('Pressed $counter times.');
prefs.setInt('counter', counter);
*/


class MyApp extends StatelessWidget 

  @override
  Widget build(BuildContext context) 
    return new MaterialApp(
        title: 'Flutter Demo',
        theme: new ThemeData(
          // This is the theme of your application.
          //
          // Try running your application with "flutter run". You'll see the
          // application has a blue toolbar. Then, without quitting the app, try
          // changing the primarySwatch below to Colors.green and then invoke
          // "hot reload" (press "r" in the console where you ran "flutter run",
          // or press Run > Flutter Hot Reload in IntelliJ). Notice that the
          // counter didn't reset back to zero; the application is not restarted.
          primarySwatch: Colors.blue,
        ),
        home: new MyHomePage(),
        routes: <String, WidgetBuilder>
          '/dashboard': (BuildContext context) => new Dashboard(),
          '/login': (BuildContext context) => new Login()
        );
  


class MyHomePage extends StatelessWidget 

   var isLoggedIn = checkActiveUser();

  @override
  Widget build(BuildContext context) 
    return new Scaffold(
        appBar: new AppBar(
          title: new Text('Demo Building'),
        ),
        body: new Container(
            child: new Center(
          child: new Column(
            children: <Widget>[new Text('DASHBOARD')],
          ),
        )));
  

如果您对不同的方法有建议,我会全力以赴!我基本上想对应用程序加载运行此检查并相应地重定向。

问候,鲍勃

更新的代码:尝试了 Hadrien 的建议,并更进一步。它现在运行,我获得了联系访问权限,但出现以下错误:

'使用不包含导航器的上下文请求导航器操作。用于从 Navigator 推送或弹出路由的上下文必须是作为 Navigator 小部件后代的小部件的上下文。'

这是更新后的代码:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:t2/helpers/currentuser.dart';

import 'screens/dashboard.dart';
import 'screens/login.dart';

void main() => runApp(new MyApp());

CurrentUser user = new CurrentUser();

checkActiveUser(BuildContext context) async 
  SharedPreferences prefs = await SharedPreferences.getInstance();

try 
  user.usr = prefs.get('usr');
  user.pwd = prefs.get('pwd');

  if (user.usr.length == 0 && user.usr.length == 0) 
    user.isLoggedIn = false;
    Navigator
        .of(context)
        .pushNamedAndRemoveUntil('/dashboard', (Route<dynamic> route) => false);
   else 
      throw new Exception('No user data found');
  
 catch (e) 
    // Send to login screen
    user.isLoggedIn = false;
    Navigator
        .of(context)
        .pushNamedAndRemoveUntil('/login', (Route<dynamic> route) => false);


  /*
// How to read/write to local storage
int counter = (prefs.getInt('counter') ?? 0) + 1;
print('Pressed $counter times.');
prefs.setInt('counter', counter);
*/


class MyApp extends StatefulWidget 
  @override
  _MyAppState createState() => new _MyAppState();


class _MyAppState extends State<MyApp> 
  void initState() 
    super.initState();
    checkActiveUser(context);
  

  @override
  Widget build(BuildContext context) 
    return new MaterialApp(
      title: 'Welcome to Flutter',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('CADSYS'),
        ),
        body: new Center(
          child: new Text('Loading...'),
        ),
      ),
     routes: <String, WidgetBuilder> 
      '/dashboard': (BuildContext context) => new Dashboard(),
      '/login': (BuildContext context) => new Login()
    ,
    );
  

【问题讨论】:

基本上,我无法在活动的 checkActiveUser 方法中访问 BuildiContext。 不知道为什么您更改了登录屏幕部分以在更新的代码中引发异常,但抛出异常来处理此类事情并不是一个好主意;只需像以前一样将该代码放在 else 块中即可。 我遇到错误时这样做了。由于没有提供数据(没有以持久状态保存的数据,因此为 null),因此长度引发了错误,因此添加 try catch 似乎是一件好事。真的不会使用 if else 进行错误处理。 如果 useruser.usr 有可能为空,最好先实际检查该情况,而不是让它抛出异常。 会考虑的。对实际问题有任何反馈吗?将不胜感激。 【参考方案1】:

我可能会做一些不同的事情...而不是在函数中推送路由,而是在 StatefulWidget 中设置登录状态,然后基于此设置 body

body: user.isLoggedIn ? new Dashboard() : new Login(),

然后您需要在代码的其他地方检查活动用户并执行setState(() user.isLoggedIn = true; );(或错误)。

当登录状态改变时,你的视图会自动更新为新的 Widget。

【讨论】:

在我看来,选择这个作为答案,它完美地完成了工作,并且是一种更简洁、更实用的方式来做我需要的事情。谢谢!【参考方案2】:

Navigator 带有 MaterialApp 小部件,因此您只能从您在其中定义的路由及其子路由访问它。 (LoginDashboardMyHomePage)。

如果您将 MyHomePage 小部件转换为有状态小部件。您将能够在initState 中调用您的checkActiveUser() 函数

initState() async 
   super.initState();
   checkActiveUser(context);

【讨论】:

接近了!但是现在出现错误:'使用不包含导航器的上下文请求导航器操作。\n''用于从导航器推送或弹出路由的上下文必须是作为导航器小部件后代的小部件的上下文。 ' 更新了一个新的代码示例,应用了您的更改。 在小部件树中,你的checkActiveUser调用应该在MaterialApp下,你把它放在同一个级别,你应该保留你的MyHomePage小部件并在里面做。

以上是关于flutter:根据不同的状态路由到不同的页面的主要内容,如果未能解决你的问题,请参考以下文章

Flutter上线项目实战——路由篇

Flutter web - 根据url设置状态[关闭]

Angular 路由器:根据用户的角色导航到不同的路由

如何根据用户的状态位置将用户重定向到不同的 index.php 页面

.Net Core Web API,根据值创建路由逻辑到具有相同路由前缀的不同控制器

颤振如何与单页网页和不同的路由网址一起工作?