Flutter:bloc,如何显示警报对话框
Posted
技术标签:
【中文标题】Flutter:bloc,如何显示警报对话框【英文标题】:Flutter: bloc, how to show an alert dialog 【发布时间】:2019-04-21 14:05:59 【问题描述】:我是集团模式和流媒体的新手。我想在按下按钮时显示一个警报对话框,但我找不到办法。其实我的代码是:
Widget button()
return RaisedButton(
child: Text('Show alert'),
color: Colors.blue[700],
textColor: Colors.white,
onPressed: ()
bloc.submit();
);
return Scaffold(
appBar: AppBar(
title: Text("Title"),
),
body: StreamBuilder(
stream: bloc.getAlert,
builder: (context, snapshot)
if (snapshot.hasData)
return Text("I have Dataaaaaa $snapshot.data");
else
return ListView(
children: <Widget>[
Container(
button()
)
...
还有 BLoC:
final _submissionController = StreamController();
Stream get submissionStream=> _submissionController.stream;
Sink get submissionSink=> _submissionController.sink;
我试图做类似的事情:
Widget button()
return StreamBuilder(
stream: submissionStream
builder: (context, snapshot)
if (snapshot.hasData)
return showDialog(...)
else
return RaisedButton(
child: Text('Show alert'),
color: Colors.blue[700],
textColor: Colors.white,
onPressed: ()
bloc.submit();
);
但是,当然,它没有用。
【问题讨论】:
【参考方案1】:构建工作时不能显示对话框。当您有新数据时,您将创建一个新的小部件。在这种情况下不使用流可能对你更好,但如果有必要,你应该使用
WidgetsBinding.instance.addPostFrameCallback((_) => yourFunction(context));
或
Future.microtask(() => showDialogFunction(context));
在你的如果
if (snapshot.hasData)
WidgetsBinding.instance.addPostFrameCallback((_) => showDialogFunction(context));
此代码将在构建方法之后启动,因此对话框将立即显示。
Bloc 函数总是返回小部件,所以当流有数据时总是返回 button() 或不同的小部件
【讨论】:
是的,在这些情况下最好避免使用 BLoC,但由于我对它很陌生,我仍然需要学习如何正确使用它。但是您建议的方式有效,所以谢谢!【参考方案2】:这就是我所做的,这可能是错误的,因为我也是 Flutter 的新手。但适用于我的场景。
Widget build(BuildContext context)
final authBloc = BlocProvider.of<AuthBloc>(context);
authBloc.outServerResponse.listen((serverResponse)
if (serverResponse.status == 'success')
_navigateToLogin();
else
_showSnakBar(serverResponse.message);
);
.... Rest of the code which returns the widget,
which in my case is form widget with button for submitting as follows,
onPressed: ()
if (_formKey.currentState.validate())
_formKey.currentState.save();
authBloc.processRegister.add(_registrationData.toMap());
outServerResponse 是 API POST 调用完成后输出的流。
authBloc.processRegister 是将表单数据传递给我的 Auth API 服务提供程序的输入接收器。
_nagivateToLogin & _showSnakBar 是简单的函数
_navigateToLogin()
Navigator.of(context).pop();
_showSnakBar(String msg)
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text(msg),
),
);
【讨论】:
似乎对于每个构建,流都会一次又一次地订阅 'authBloc.outServerResponse.listen' 我认为订阅必须关闭。 @RideSun 是真的。如果它是有状态的并在 dispose 时关闭,最好将其置于 initstate 中。【参考方案3】:您可以使用BlocListener 显示对话框、Snackbars 或导航到新页面。
使用这种方法,您可能希望重构以依赖 bloc 状态而不是直接访问流。
return Scaffold(
appBar: AppBar(
title: Text("Title"),
),
body: BlocProvider<YourBloc>(
create: () => YourBloc(),
child: Stack([
SnackbarManager(),
YourScreen(),
]),
),
);
...
/// This is basically an empty UI widget that only
/// manages the snackbar
class SnackbarManager extends StatelessWidget
@override
Widget build(BuildContext context)
return BlocListener<YourBloc, YourBlocState>(
listener: (context, state)
if (state.hasMyData)
Scaffold.of(context).showSnackBar(SnackBar(
content:
Text("I got data"),
));
,
child: Container(),
);
【讨论】:
我正在尝试使用 bloc 在对话框中显示未来的数据,我不明白您在使用堆栈时的意思[SnackBarManager(), screen()]在这种情况下是否堆栈允许screen和blockListener同时运行?【参考方案4】:这个过程对我有用。 我在返回小部件之前调用了我的对话框
Future.microtask(() => showLoginSuccess(BuildContext context));
【讨论】:
【参考方案5】:我知道我迟到了,但也许这会对某人有所帮助。 我目前正在自己学习 BLoC 并遇到了类似的问题。
首先,我想推荐flutter_bloc package from pub.dev。
它包含可以帮助您解决此问题的小部件,例如 BlocListener
和 BlocConsumer
。
如果您想不使用它,您可以尝试分别使用StatefulWidget
和listen
并使用您的逻辑来显示对话框。 (还要确保您的流在我的示例中进行广播,因此它可以有多个侦听器)
我做了一个例子,你可以复制到dartpad.dev/flutter:
import 'dart:async';
import 'package:flutter/material.dart';
final myStream = StreamController<bool>.broadcast();
void main()
runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
theme: ThemeData.dark(),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
class MyWidget extends StatefulWidget
@override
_MyWidgetState createState() => _MyWidgetState();
class _MyWidgetState extends State<MyWidget>
initState()
super.initState();
myStream.stream.listen((show)
if(show)
showDialog(
barrierDismissible: false,
context: context,
builder: (context)
return AlertDialog(
title: Text('MyDialog'),
actions: [
TextButton(
child: Text('Close'),
onPressed: ()
myStream.sink.add(false);
),
]
);
);
if(!show)
Navigator.pop(context);
);
@override
Widget build(BuildContext context)
return Center(child: ElevatedButton(
child: Text('Show Alert'),
onPressed: ()
myStream.sink.add(true);
));
【讨论】:
【参考方案6】:我通过如下维护两个上下文来解决它 **
BlocProvider of type A ==>widget class B(showdialog(context:context,builder(context2)
Blocprvider.value(value:Blocprovider.of<A>.context)
child:BlocListener(
listner(context2,state)
//
your works
//
child:AlertDialog( some widgets
a button function ()=> context.read<A>().function or property name
//
1.这里我们称之为旧上下文实际上它是向提供者注册的,2.上下文2仅用于构建新的构建器小部件。 3.因此我们通过导航获得 bloc 并在导航警报小部件中访问而无需创建它
【讨论】:
以上是关于Flutter:bloc,如何显示警报对话框的主要内容,如果未能解决你的问题,请参考以下文章