Flutter: bloc, how to show an alert dialog

前端 未结 5 1693
佛祖请我去吃肉
佛祖请我去吃肉 2021-02-19 19:01

I´m new in the bloc pattern and stream stuff. I want to show up an alert dialog when I press a button, but I can´t find a way to do it. Actually my code is:

Widg         


        
相关标签:
5条回答
  • 2021-02-19 19:41

    I know I'm late to the party, but maybe this will help someone. I'm currently learning about BLoC myself and ran into a similar problem.

    First of all, I want to recommend the flutter_bloc package from pub.dev. It contains Widgets that help you with this like BlocListener and BlocConsumer.

    If you want to go without it, you could try using a StatefulWidget and listen to it separately and use your logic to show the dialog. (also make sure your stream is broadcasting as in my example, so it can have multiple listeners)

    I've made an example which you could copy-past into 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);
        }));
      }
    }
    
    0 讨论(0)
  • 2021-02-19 19:48

    You can use BlocListener for showing Dialogs, Snackbars or for navigating to a new page.

    With this approach you may want to refactor to rely on the bloc state rather than accessing the stream directly.

    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(),
        );
      }
    }
    
    0 讨论(0)
  • 2021-02-19 19:51

    this process working for me. I called my Dialog before return the widget

    Future.microtask(() => showLoginSuccess(BuildContext context));

    0 讨论(0)
  • 2021-02-19 19:52

    You can't show a dialog when build working. When you have new data, then you create a new widget. Probably better for you will be not using the stream in this case, but if it necessary you should use

    WidgetsBinding.instance.addPostFrameCallback((_) => yourFunction(context));

    or

    Future.microtask(() => showDialogFunction(context));

    in your if

    if (snapshot.hasData) { WidgetsBinding.instance.addPostFrameCallback((_) => showDialogFunction(context)); }

    This code will be launched after build method, so dialog will show immediately.

    Bloc function always return widget, so always return button() or different wiget when stream has data

    0 讨论(0)
  • 2021-02-19 19:55

    Here is what I did, it might be wrong as I'm also new to flutter. But works for my scenario.

    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 is the stream that outputs after finishing API POST call.

    authBloc.processRegister is the input sink to pass form data to my Auth API Service Provider.

    _nagivateToLogin & _showSnakBar are simple functions

    _navigateToLogin() {
          Navigator.of(context).pop();
    }
    
    _showSnakBar(String msg) {
         Scaffold.of(context).showSnackBar(
          SnackBar(
            content: Text(msg),
          ),
         );
     }
    
    0 讨论(0)
提交回复
热议问题