如何在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