如何在flutter中从streambuilder导航到其他页面?

Posted

技术标签:

【中文标题】如何在flutter中从streambuilder导航到其他页面?【英文标题】:how to navigate to other page from streambuilder in flutter? 【发布时间】:2020-07-29 06:35:24 【问题描述】:

我正在尝试在 Flutter 中使用 bloc 模式实现登录功能。所以我想在身份验证成功后导航到主页。从 loginBloc.dart 中,当状态为成功时,我将在 login.dart 中的 streamBuilder 中获取状态我想导航到 main.dart,但我无法理解如何在 login.dart 中的 streamBuilder 中调用 main.dart。

登录.dart


import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_svg/svg.dart';
import 'package:hotelorders/bloc/LoginBloc.dart';
import 'package:hotelorders/screens/Home.dart';

class Login extends StatefulWidget

  @override
  State<StatefulWidget> createState() 
    return LoginState();
  


class LoginState extends State<Login>

  final LoginBloc _loginBloc = LoginBloc();
  String _email,_password;
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  @override
  void dispose()
  
    _loginBloc.dispose();
    super.dispose();
  
  Widget _progressBar()
  
    return StreamBuilder<bool>(
      stream: _loginBloc.progressStream,
      builder: (BuildContext context,AsyncSnapshot<bool> snapShot) 
        bool visible;
        if(snapShot.data == null)
          
            visible = false;
          
        else
          
            visible = snapShot.data;
          
        return Visibility(
          maintainSize: true,
          maintainAnimation: true,
          maintainState: true,
          visible: visible,
          child: Container(
              child: Center(
                  child: SizedBox(
                    width: 60,
                    height: 60,
                    child: Stack(
                      children: <Widget>[
                        Container(
                          decoration: BoxDecoration(
                            shape: BoxShape.circle,
                            color: Colors.white,
                            boxShadow: [
                              BoxShadow(
                                color: Colors.grey,
                                offset: Offset(0.0, 1.0), //(x,y)
                                blurRadius: 1.0,
                              ),
                            ],
                          ),
                        ),
                        Center(
                          child: CircularProgressIndicator(),
                        )
                      ],
                    ),
                  )
              )
          ),
        );
      
    );
  
  Widget _emailTextField()
  
    return TextFormField(
      decoration: InputDecoration(
        labelText: "Email id",
        border: OutlineInputBorder(
          borderRadius: new BorderRadius.circular(32.0),
        )
      ),
      keyboardType: TextInputType.emailAddress,
      validator: (String value)
        if(value.isEmpty || !RegExp(r"[a-z0-9!#$%&'*+/=?^_`|~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`|~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?").hasMatch(value))
          
            return "Enter a valid email id";
          
        return null;
      ,
      onSaved: (String value)
        _email = value;
      ,
    );
  
  Widget _passwordTextField()
  
    return TextFormField(
      decoration: InputDecoration(labelText: "Password",
          filled: true,

          border: OutlineInputBorder(
            borderRadius: new BorderRadius.circular(32.0),
          ),
          fillColor: Colors.white
      ),
      keyboardType: TextInputType.text,
      obscureText: true,
      validator: (String value)
        if(value.isEmpty)
          
            return "Enter a valid password";
          
        else if(value.length < 8)
          
            return "Password is too short";
          
        else
          
            return null;
          
      ,
    );
  
  void _login()
  

    if(!_formKey.currentState.validate())
      
        return;
      
    _formKey.currentState.save();

    Map<String,String> map = new Map();
    map['email'] = _email;
    map['password'] = _password;
    _loginBloc.login(map);
  
  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: Stack(
        children: <Widget>[
          SingleChildScrollView(
              child: Container(
                child: Column(
                  children: <Widget>[
                    Container(
                      alignment: Alignment.center,
                      margin: EdgeInsets.fromLTRB(0, 48, 0, 0),
                      child: Text(
                        "Take Orders and",
                        style: TextStyle(color: Theme.of(context).primaryColorDark,fontSize: 20),
                      ),
                    ),
                    Container(
                      child: Text(
                        "Track the Best Selling Items",
                        style: TextStyle(color: Theme.of(context).primaryColor,fontSize: 16),
                      ),
                    ),
                    Container(
                      margin: EdgeInsets.fromLTRB(16, 0, 16, 0),
                      child: SvgPicture.asset('assets/images/undraw_booking.svg',width: 100.0,height: 280.0,),
                    ),
                    Container(
                      margin: EdgeInsets.fromLTRB(16, 0, 0, 0),
                      child:Row(
                        children: <Widget>[
                          Text(
                              "Login To ",
                              style: TextStyle(color: Colors.black,fontSize: 20)
                          ),
                          Text(
                            "Take orders",
                            style: TextStyle(color: Theme.of(context).primaryColorDark,fontSize: 20),
                          )
                        ],
                      ),
                    ),
                    Container(
                      margin: EdgeInsets.fromLTRB(16, 8, 16, 0),
                      child: Form(
                        key: _formKey,
                        child: Column(
                          children: <Widget>[
                            Container(
                              margin: EdgeInsets.fromLTRB(0, 8, 0, 0),
                              child:  _emailTextField(),
                            ),
                            Container(
                              margin: EdgeInsets.fromLTRB(0, 8, 0, 0),
                              child:  _passwordTextField(),
                            ),
                            Container(
                              margin: EdgeInsets.fromLTRB(0, 8, 0, 0),
                              child: Align(
                                alignment: Alignment.centerLeft,
                                child: RaisedButton(
                                  shape: RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(32.0)
                                  ),
                                  padding: EdgeInsets.fromLTRB(64, 12, 64, 12),
                                  color: Theme.of(context).accentColor,
                                  textColor: Colors.white,
                                  child: Text(
                                    "Login",
                                  ),
                                  onPressed: ()
                                    _login();
                                  ,
                                ) ,
                              ),
                            ),
                            StreamBuilder<dynamic>(
                              stream:_loginBloc.loginStateStream,
                              builder: (BuildContext context, AsyncSnapshot<dynamic> snapShot)
                                if(snapShot.data == "success")
                                  
//                                    WidgetsBinding.instance.addPostFrameCallback((_)
//                                      Navigator.push(context, MaterialPageRoute(
//                                          builder: (context)=> Home()
//                                      ));
//                                    );
                                  
                                else if(snapShot.data != null && snapShot.data != "success")
                                  
                                    WidgetsBinding.instance.addPostFrameCallback((_) 
                                      Scaffold.of(context).showSnackBar(SnackBar(
                                        content: Text('$snapShot.data',
                                          style: TextStyle(color: Colors.black),),
                                        backgroundColor: Color(0xFFe5e5e5),
                                      ));
//                                      showDialog(context: context,builder: (BuildContext con)
//                                        return AlertDialog(
//                                          title: Text('$snapShot.data'),
//                                        );
//                                      );
                                    );
                                  

                                return Container();
                              ,
                            )
                          ],
                        ),
                      ),

                    )

                  ],
                ),
              )
          ),
          _progressBar(),
        ],
      ),
    );
  


LoginBloc.dart

import 'dart:async';


class LoginBloc

  // here event comes in and state goes out
  //stream conntroller for output
  final _loginStateController = StreamController<String>();
  //stream controller for input
  final _loginEventController = StreamController<Map<String,String>>();

  final _progressController = StreamController<bool>();

  StreamSink<String> get loginStateSink => _loginStateController.sink;
  Stream<String> get loginStateStream => _loginStateController.stream;

  Sink<Map<String,String>> get loginEventSink => _loginEventController.sink;

  Stream<bool> get progressStream => _progressController.stream;
  StreamSink<bool> get progressSink => _progressController.sink;


  LoginBloc()
  
    progressSink.add(false);
    _loginEventController.stream.listen(login);

  

  login(Map<String,String> loginDetails)
  
    progressSink.add(true);
    Timer(Duration(seconds: 3), () 
      progressSink.add(false);
      loginStateSink.add("success");
    );
    // when we pass data in sink we get the  output from stream

  
  void dispose()
  
    _loginEventController.close();
    _loginStateController.close();
    _progressController.close();
  


【问题讨论】:

【参考方案1】:

你快到了。以下应该有效:

if(snapShot.data == "success")


    Navigator.push(
        context, MaterialPageRoute(builder: (context)=> Home()));


注意:WidgetsBinding.instance.addPostFrameCallback 用于在加载小部件树时获取回调。

【讨论】:

hi sukhi 感谢您的回复,但如果添加上述代码 .setState() 或 markNeedsBuild() 在构建期间调用,我会收到错误消息。这个 Overlay 小部件不能被标记为需要构建,因为框架已经在构建小部件的过程中。仅当其祖先之一当前正在构建时,小部件才能在构建阶段标记为需要构建。这个例外是允许的,因为框架在子组件之前构建父窗口小部件,这意味着将始终构建脏后代。否则,框架可能不会在此构建阶段访问此小部件。

以上是关于如何在flutter中从streambuilder导航到其他页面?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Flutter 的 StreamBuilder 中使用 Future [重复]

如何在 Flutter 中嵌套 StreamBuilder?

如何在 Flutter Web 上使用 StreamBuilder 和 Firestore?

如何在 StreamBuilder 中更新 Flutter Cards 而无需重置状态?

如何在 Flutter 中使用 Firestone 的 streambuilder 获取嵌套文档?

如何在 Firebase + Firestore + Flutter 中使用 StreamBuilder 将所有子集合数据获取到 Widget