如何在 Flutter 中创建登录墙视图

Posted

技术标签:

【中文标题】如何在 Flutter 中创建登录墙视图【英文标题】:How to create Login-Wall Views in Flutter 【发布时间】:2019-11-11 13:35:33 【问题描述】:

我正在使用 Flutter 开发一个应用程序,我对它/Dart 很陌生。我已经创建了登录、注册等,一切正常。现在我想为每个需要用户登录的 View 创建一个“Login-Wall”模板。如果用户没有登录,他应该返回到 LoginView,如果 api-call 仍在加载,它应该只显示一个名为 LoadingView() 的加载屏幕。我首先创建了一个名为 AuthorizedLayout 的有状态小部件:

class AuthorizedLayout extends StatefulWidget 
  final Widget view;

  AuthorizedLayout(this.view);

  _AuthorizedLayoutState createState() => new _AuthorizedLayoutState();

状态使用 Future Builder 如下:

  Widget build(BuildContext context) 
    return FutureBuilder<User>(
      future: futureToken,
      builder: (BuildContext context, AsyncSnapshot<User> snapshot) 
        switch (snapshot.connectionState) 
          case ConnectionState.none:
            return NoConnectionView();
          case ConnectionState.active:
          case ConnectionState.waiting:
            return LoadingView();
          case ConnectionState.done:
            if(snapshot.data != null) 
              print("User Data loaded");
              return widget.view;
             else
              return LoginView();
        
      ,
    );
  

如您所见,它应该加载用户数据,并在完成后返回视图。 futureToken 表示 Future 将在 api 请求后从服务器返回用户对象。在任何其他情况下,它应该显示加载/错误/登录页面。

我这样称呼它:

  Widget build(BuildContext context) 
    return Scaffold(
      backgroundColor: Theme.of(context).backgroundColor,
      body: AuthorizedLayout(
        view: DashboardView(),
      ),
    );
  

在仪表板视图的 Build 方法中,我有一个“print('Dashboard View');”。我遇到的问题是,在输出中,在“加载用户数据”之前打印了“仪表板视图”。这意味着我无法访问该视图中加载的用户数据。这意味着此解决方案无法按我的预期工作。

现在我的问题是:有什么方法可以构建这个“登录墙”并将用户数据传递给登录墙内的每个视图?我希望我发布的代码能够解释我想要实现的想法。

【问题讨论】:

【参考方案1】:

所以我才知道发生了什么。我将已经构建的小部件传递给 AuthorizedView。我实际上必须传递的是 Builder 而不是 Widget。

class AuthorizedLayout extends StatefulWidget 
  final Builder viewBuilder;

  AuthorizedLayout(this.viewBuilder);

  _AuthorizedLayoutState createState() => new _AuthorizedLayoutState();

这样称呼它:

  Widget build(BuildContext context) 
    return Scaffold(
      backgroundColor: Theme.of(context).backgroundColor,
      body: AuthorizedLayout(
        viewBuilder: Builder(builder: (context) => DashboardLayout()),
      ),
    );
  

请注意,与上面的示例相比,我将 final 变量调用为 viewBuilder 而不是 view。

这实际上将在加载用户数据后构建小部件。

【讨论】:

【参考方案2】:

有什么方法可以构建这个“登录墙”并将用户数据传递到登录墙内的每个视图?

绝对!在基本层面上,您正在谈论状态管理。用户登录您的应用后,您希望存储该用户数据,以便小部件树中的任何小部件都可以访问它。

Flutter 中的状态管理是一个备受争议的话题,虽然有很多选择,但实际上并没有适合每个应用程序的状态管理技术。也就是说,我会从简单的开始。 scoped_model 包是最简单和最受欢迎的选项之一。

您可以阅读所有详细信息 here,但要点是它提供了实用程序来将数据模型从父窗口小部件传递到其后代。

首先,install the package。

其次,您需要创建一个模型,该模型可以保存您希望树中的任何小部件都可以访问的用户数据。下面是一个简单的例子:

// user_model.dart
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';

class UserModel extends Model 
  dynamic _userData;

  void setUserData(dynamic userData) 
    _userData = userData;
  

  String getFirstName() 
    return _userData['firstName'];
  

  static UserModel of(BuildContext context) =>
      ScopedModel.of<UserModel>(context);

接下来,我们需要让这个UserModel 的一个实例可供所有小部件使用。一种人为的做法是将整个应用程序包装在ScopedModel 中。示例如下:

// main.dart
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
import 'login_view.dart';
import 'user_model.dart';

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

class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return ScopedModel<UserModel>(
      model: UserModel(),
      child: MaterialApp(
        theme: ThemeData.light(),
        home: LoginView(),
      ),
    );
  

在上面的代码中,我们将整个MaterialApp 实例包装在ScopedModel&lt;UserModel&gt; 中,这将使应用程序中的每个小部件都可以访问User 模型。

在您的登录代码中,您可以在按下登录按钮时执行以下操作:

onPressed() async 
    // authenticate your user...
    var userData = await someApiCall();

    // set the user data in our model
    UserModel.of(context).setUserData(userData);

    // go to the dashboard
    Navigator.push(
        context,
        MaterialPageRoute(
            builder: (context) => DashboardView(),
        ),
    );

最后但同样重要的是,您可以通过UserModel 访问该用户数据,如下所示:

// dashboard_view.dart
import 'package:flutter/material.dart';
import 'package:scoped_model_example/user_model.dart';

class DashboardView extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Center(
          child: Text(
            UserModel.of(context).getFirstName(),
          ),
        ),
      ],
    );
  

查看scoped_model 上的文档了解更多详情。如果您需要更高级的东西,Flutter 中还有许多其他状态管理模式,例如 BloC、Redux、Mobx、Provider 等等。

【讨论】:

嗨!感谢您的回答。我目前使用单例模式的 DataDelegate 解决了全局信息的数据传递问题。但是,我实际上不确定我的解决方案是否是不好的做法。您认为放弃我的解决方案而选择您的解决方案值得吗? 我并不是说你应该放弃现有的东西,但是如果你的应用程序增长,你可能会受益于使用 Flutter 中更常用的状态管理模式之一。它们很可能更具可扩展性、经过全面测试,而且您很可能会找到更多帮助。

以上是关于如何在 Flutter 中创建登录墙视图的主要内容,如果未能解决你的问题,请参考以下文章

如何在Flutter / Dart中创建异步回调?

如何在 Flutter Web 中创建 DOM 元素并使用 ID 声明它

Flutter Cards:如何在 Flutter 中创建自定义卡片小部件

如何在 Flutter 中创建圆形图标按钮?

如何使用 Flutter 在 MaterialApp 中创建卡片

如何在 Flutter 中创建 HTTP 服务器应用程序?