FLUTTER:如何在流构建器中使用导航器?

Posted

技术标签:

【中文标题】FLUTTER:如何在流构建器中使用导航器?【英文标题】:FLUTTER: How to use navigator in streambuilder? 【发布时间】:2020-05-01 11:47:04 【问题描述】:

我正在尝试在流构建器中导航,但出现以下错误:“setState() 或 markNeedsBuild() 在构建期间调用。”。如果我在按下的按钮内调用导航,它可以工作,但不能仅在条件内使用它。我被困住了。有一些代码给你看。

Widget build(BuildContext context) 
    return Scaffold(
      body: StreamBuilder(
        stream:
            Firestore.instance.collection('rooms').document(pinid).snapshots(),
        builder: (BuildContext context, AsyncSnapshot snapshot) 
          if (snapshot.hasData) 
            if ((snapshot.data['Votes'][0] + snapshot.data['Votes'][1]) >=
                snapshot.data['joueurs']) 
              Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => Results(),
                  ));
            
          
          return Center(
            child: Text('VOUS AVEZ VOTE'),
          );
        ,
      ),
    );
  

【问题讨论】:

【参考方案1】:

这是因为当您尝试导航到另一个屏幕时,Flutter 会触发框架构建,因此这是不可能的。

您可以安排后帧回调,以便在 Flutter 完成该小部件的树重建后立即导航。

import 'package:flutter/foundation.dart';

  WidgetsBinding.instance.addPostFrameCallback(
     (_) => Navigator.push(context,
       MaterialPageRoute(
         builder: (context) => Results(),
       ),
     ),
   );

【讨论】:

感谢您的回答!我把你的代码放在我的 if 条件下,但它重新加载了很多时间,就像它多次调用 Result 一样:/ 那是因为该流正在下沉很多事件。您必须确保每个事件只导航一次。 拯救了我的一天 【参考方案2】:

如果导航是按钮按下时唯一发生的事情,我根本不会使用 Bloc,因为导航不是业务逻辑,应该由 UI 层完成。

如果您在按钮按下时具有业务逻辑并且需要根据一些动态信息进行导航,那么我将在表示层(小部件)中再次进行导航以响应如下所示的成功状态。您还可以根据需要更改导航逻辑。

Widget loginButton(LoginBloc loginBloc) =>
      StreamBuilder<List<UserLoginResultElement>>(
          stream: loginBloc.loginStream,
          builder:
              (context, AsyncSnapshot<List<UserLoginResultElement>> snapshot) 
            print(snapshot.connectionState);
            Widget children;
            if (snapshot.hasError) 
              children = Padding(
                padding: const EdgeInsets.only(top: 16),
                child: Text('Error: $snapshot.error'),
              );
             else 
              switch (snapshot.connectionState) 
                case ConnectionState.none:
                case ConnectionState.waiting:
                case ConnectionState.done:
                case ConnectionState.active:
                  children = BlockButtonWidget(
                    text: Text(
                      "LOGIN",
                      style: TextStyle(color: Theme.of(context).primaryColor),
                    ),
                    color: Theme.of(context).accentColor,
                    onPressed: () async 
                      try 
                        bloc.submit(_userNameController.value.text,
                            _passwordController.value.text, context);
                       catch (ex) 
                        print(ex.toString());
                      
                    ,
                  );
                  break;
              
            
            if (snapshot.data != null && snapshot.hasData) 
              if (snapshot.data[0].code == "1") 

                SchedulerBinding.instance.addPostFrameCallback((_) 
                 Navigator.pushReplacementNamed(context, "/HomeScreen");
                );
               else 
                print(Login Failed');
              
            
            return children;
          );

【讨论】:

以上是关于FLUTTER:如何在流构建器中使用导航器?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter/Firestore - 在流构建器中的动态列表视图上实现“分页”

Flutter 流构建器概念

在 Flutter 的流构建器中使用 Future 构建器是正确的

Flutter:当我抛出异常时,构建器在未来的构建器中调用了两次

无法在列表视图构建器中测试没有大小的渲染框

Flutter:从 StreamBuilder 构建器回调内部导航到另一个屏幕