在StreamBuilder中两次调用了方法,该方法在Flutter中包含自定义对话框

时间:2019-08-16 09:07:56

标签: flutter dialog stream-builder

  • 我创建一个加载对话框并将其放入StreamBuilder中。同时,有一个名为_loadingText的方法作为对话框参数。当我单击“开始运行”按钮时,_loadingText方法将被调用两次。
  • 以同样的方式,我使用了flutter内置对话框showAboutDialog,一切正常。
  • 如果我删除StreamBuilder,则_loadingText也将被调用一次。

这需要我一天!

感谢您的帮助。预先感谢...

  • main.dart:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:view_animation/loading_dialog.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  StreamController<String> _streamController;

  TextEditingController _inputController;

  @override
  void initState() {
    super.initState();
    _streamController = StreamController<String>.broadcast();

    _inputController = TextEditingController();
    _inputController.addListener(() {
      _streamController.add(_inputController.text);
    });
  }

  @override
  void dispose() {
    super.dispose();
    _streamController.close();
  }

  String _loadingText() {
    print('===== 2. Method run OVER =====');
    return 'Loading...';
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          _inputContainer(),
          SizedBox(
            height: 20,
          ),
          Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(26),
            ),
            child: StreamBuilder(
              stream: _streamController.stream.map((text) => text.length > 4),
              builder: (context, snap) {
                return FlatButton(
                  color: Color(0xFFFFAC0B),
                  disabledColor: Colors.black12,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(26),
                  ),
                  padding: EdgeInsets.symmetric(vertical: 15, horizontal: 12.5),
                  onPressed: snap.data != null && snap.data
                      ? () {
                          print('===== 1. show dialog =====');
                          showDialog(
                              context: context,
                              builder: (BuildContext context) {
                                return LoadingDialog(
                                  loadingText: _loadingText(),
                                );
                              });
                          // showAboutDialog(context: context, applicationName: _loadingText());
                        }
                      : null,
                  child: Text(
                    'GO RUN',
                    style: TextStyle(fontSize: 12, color: Colors.white),
                  ),
                );
              },
            ),
          ),
        ],
      )),
    );
  }

  Widget _inputContainer() {
    return Container(
      width: 200,
      padding: EdgeInsets.only(left: 20, right: 20),
      decoration: BoxDecoration(
        color: Color(0xFFFFAC0B),
        borderRadius: BorderRadius.circular(36.0),
      ),
      child: TextField(
        controller: _inputController,
        keyboardType: TextInputType.number,
        maxLines: 1,
        cursorColor: Colors.orange,
        style: TextStyle(
          color: Colors.white,
          fontSize: 24,
        ),
        decoration: InputDecoration(
          border: InputBorder.none,
          hintText: "Let's GO",
          hintStyle: TextStyle(color: Colors.white54, fontSize: 20),
        ),
      ),
    );
  }
}
  • loading_dialog.dart
import 'package:flutter/material.dart';

class LoadingDialog extends StatefulWidget {
  final String loadingText; 
  final bool outsideDismiss; 

  final Function dismissCallback;
  final Future<dynamic> requestCallback;

  LoadingDialog(
      {Key key,
      this.loadingText = "Loading...",
      this.outsideDismiss = true,
      this.dismissCallback,
      this.requestCallback,
      })
      : super(key: key);
  @override
  _LoadingDialogState createState() => _LoadingDialogState();
}

class _LoadingDialogState extends State<LoadingDialog> {

  void _dismissDialog(){
    if(widget.dismissCallback != null) {
      widget.dismissCallback();
    }
    Navigator.of(context).pop();
  }

  @override
  void initState() {
     print('===== 3. loading init =====');
    if (widget.requestCallback != null) {
      widget.requestCallback.then((_) => Navigator.of(context).pop());
    }
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: widget.outsideDismiss ? _dismissDialog : null,
      child: Material(
        type: MaterialType.transparency,
        child: Center(
          child: SizedBox(
            width: 120.0,
            height: 120.0,
            child: Container(
              decoration: ShapeDecoration(
                color: Colors.white,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(8.0)
                ),
              ),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  new CircularProgressIndicator(),
                  new Padding(
                    padding: const EdgeInsets.only(
                      top: 20.0,
                    ),
                    child: new Text(
                      widget.loadingText,
                      style: new TextStyle(fontSize: 12.0),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

2 个答案:

答案 0 :(得分:0)

那是因为,当您第一次点击按钮时,您的TextField仍然处于活动状态,这意味着出现了新状态,并且flutter会重新构建。当您第二次点击按钮时,您的文本字段处于非活动状态。

答案 1 :(得分:0)

要点是,当您将函数传递给 onTap 小部件时,它将在构建状态并调用函数而不点击时调用:

因此,请不要尝试将类似方法传递给 OnTap

@override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () widget.outsideDismiss ? ()
      {
      this._dismissDialog();
      } : null,
      ...