0

我在 Flutter 项目中添加了一个弹出窗口(alertdialog),该项目有一个流构建器。起初它不起作用,但在使其异步并添加如下代码之后

await Future.delayed(Duration(milliseconds: 50));

它开始工作正常。此弹出窗口将在数据库中的特定数据更改后发生。后来我想在我的项目中添加第二个弹出窗口以获得第二个数据库值,不同之处在于这个有一个用于用户输入的文本字段和一个用于此的控制器。当我尝试这个弹出窗口时效果很好,但在弹出窗口的后面它给出了

type 'Future<dynamic>' is not a subtype of type 'Widget'

带有红色/黄色错误背景的错误。这两个弹出窗口之间的区别就像我说的其中一个有输入控制器,我在这里做错了什么?

这是完整的代码:

   import 'dart:math';
    
    import 'package:flutter/material.dart';
    import 'package:assets_audio_player/assets_audio_player.dart';
    import 'package:flutter/scheduler.dart';
    import 'numbers.dart';
    import 'package:firebase_auth/firebase_auth.dart';
    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:firebase_core/firebase_core.dart';
    import 'package:sayi_avi/homescreen.dart';
    
    
    Numbers myNumbers = Numbers();
    
    void main(){
      runApp(
          GameScreen()
      );
    }
    
    class GameScreen extends StatefulWidget {
      static String id ='gamescreen';
    
      @override
      _GameScreenState createState() => _GameScreenState();
    }
    
    class _GameScreenState extends State<GameScreen> {
      bool _initialized = false;
      bool _error = false;
      TextEditingController _controller;
    
      void initializeFlutterFire() async {
        try {
          // Wait for Firebase to initialize and set `_initialized` state to true
          await Firebase.initializeApp();
          setState(() {
            _initialized = true;
          });
        } catch(e) {
          // Set `_error` state to true if Firebase initialization fails
          setState(() {
            _error = true;
          });
        }
      }
    
      @override
      void initState() {
        initializeFlutterFire();
        super.initState();
        getCurrentUser();
        _controller = TextEditingController();
      }
    
      void dispose() {
        _controller.dispose();
        super.dispose();
      }
    
      final _auth =FirebaseAuth.instance;
      User loggedInUser;
      final _firestore = FirebaseFirestore.instance;
      final String collectionPath = 'users';
      String docPath;
      var userPath;
      DocumentReference userdoc;
      var userSnapshot;
      String gameResult;
      String sendednumber='';
      List<dynamic> kullanicisayilari = [];
      List<dynamic> rakipsayilari = [];
      List<dynamic> sonuc = [];
    
    
      void getCurrentUser() async{
        try{
          final user = await _auth.currentUser;
          if(user !=null){
            loggedInUser =user;
            docPath = loggedInUser.uid;
            userPath = _firestore.collection(collectionPath);
            userdoc = userPath.doc(docPath);
            userSnapshot = userdoc.snapshots();
          }
        }catch(e){
          print(e);
        }
      }
    
      Expanded attachNumber(number,imagenumber){
        return Expanded(
          child:FlatButton(
            onPressed: (){
              setState(() {
                if(!myNumbers.numberStatus[1]){
                  myNumbers.buttonValues['numberimage1'] = imagenumber;
                  myNumbers.numberStatus[1] =true;
                  myNumbers.decimals[1]=number;
                }else if(!myNumbers.numberStatus[2]){
                  myNumbers.buttonValues['numberimage2'] = imagenumber;
                  myNumbers.numberStatus[2] =true;
                  myNumbers.decimals[2]=number;
                }else if(!myNumbers.numberStatus[3]){
                  myNumbers.buttonValues['numberimage3'] = imagenumber;
                  myNumbers.numberStatus[3] =true;
                  myNumbers.decimals[3]=number;
                }else if(!myNumbers.numberStatus[4]){
                  myNumbers.buttonValues['numberimage4'] = imagenumber;
                  myNumbers.numberStatus[4] =true;
                  myNumbers.decimals[4]=number;
                }
              });
              final assetsAudioPlayer = AssetsAudioPlayer();
              assetsAudioPlayer.open(
                Audio("assets/audios/click.wav"),
              );
            },
            padding: EdgeInsets.all(0),
            child: Image.asset('images/$imagenumber'),
          ),
        );
      }
    
      Expanded showDeleteNumbers(statusNumber,number){
        return Expanded(
            child:FlatButton(
              onPressed: (){
                setState(() {
                  myNumbers.decimals[statusNumber]='';
                  myNumbers.numberStatus[statusNumber] =false;
                  myNumbers.buttonValues[number] = 'nonumber.png';
                });
              },
            child: Image.asset('images/'+myNumbers.buttonValues['$number']),
            ),
        );
      }
    
      Future<void> sendnumber() {
        sendednumber="";
        for (var numbers in myNumbers.decimals.values){
          sendednumber = sendednumber+numbers;
        }
        Random rnd;
        int min = 10000;
        int max = 100000;
        rnd = new Random();
        var r = min + rnd.nextInt(max - min);
        kullanicisayilari.add(sendednumber+"|"+r.toString());
        return userPath
            .doc(docPath)
            .update({'atilansayi': kullanicisayilari})
            .then((value) => print("User Updated"))
            .catchError((error) => print("Failed to update user: $error"));
      }
      /*
      List<Widget> getUserNumbers(){
        return
      }
    
       */
    
      Text getUserNumbers(kullanicisayilari){
        for(var number in kullanicisayilari){
        return Text(number);
          };
      }
    

//This one is working fine


      _showMaterialDialog(String type) async{
        if(type=="win"){
          gameResult = "You Win, Gratz!";
        }else if(type=="lose"){
          gameResult = "You Lose :(";
        }
        print("buraya girdi");
        print(gameResult);
        await Future.delayed(Duration(milliseconds: 50));
        showDialog (
            context: context,
            builder: (_) => AlertDialog(
              title: Text("Result"),
              content: Text(gameResult),
              actions: <Widget>[
                FlatButton(
                  child: Text('Close'),
                  onPressed: () {
                      Navigator.pushNamed(context, HomeScreen.id);
                  },
                )
              ],
            ));
      }

//This one is causing errors



      _showMaterialDialogNumber() async{
        await Future.delayed(Duration(milliseconds: 100));
        showDialog (
            context: context,
            builder: (_) => AlertDialog(
              title: Text("Start"),
              content: TextField(
                controller: _controller,
                obscureText: true,
                decoration: InputDecoration(
                  border: OutlineInputBorder(),
                  labelText: 'Enter your Number',
                ),
              ),
              actions: <Widget>[
                FlatButton(
                  child: Text('Submit'),
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                )
              ],
            ));
      }
    
      /*
    
       */
    
    
      @override
      Widget build(BuildContext context) {
        if(_error) {
          return Text('error-game', textDirection: TextDirection.ltr);
        }
    
        // Show a loader until FlutterFire is initialized
        if (!_initialized) {
          return Text('Loading', textDirection: TextDirection.ltr);
        }
        return StreamBuilder<DocumentSnapshot>(
          stream: userSnapshot,
          builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
            if (snapshot.hasError) {
              return Text('Something went wrong');
            }
    
            if (snapshot.connectionState == ConnectionState.waiting) {
              return Text("Loading");
            }
            if(snapshot.hasData){
              Map<String, dynamic> userDocument  = snapshot.data.data();
              print(collectionPath);
              print(docPath);
              print(snapshot.data);
              print(userDocument);
              gameResult = userDocument['status'];

//This one works fine

              if(gameResult =="win" || gameResult =="lose"){
                return _showMaterialDialog(gameResult);
              }

//This one causing errors


              if(gameResult=="on"){
                return _showMaterialDialogNumber();
              }
              kullanicisayilari = userDocument['atilansayi'];
              List<dynamic> kullanicisayilariDuz = [];
              List<dynamic> rakipsayilariDuz = [];
              List<dynamic> sonuclarDuz = [];
              for (var numbers in kullanicisayilari){
                var splittedNumber = numbers.split('|');
                kullanicisayilariDuz.add(splittedNumber[0]);
              }
              rakipsayilari = userDocument['rakipsallama'];
              sonuc = userDocument['sonuc'];
              for (var sonuclar in sonuc){
                var splittedSonuc = sonuclar.split('|');
                sonuclarDuz.add(splittedSonuc[0]);
              }
              for (var rakipsayi in rakipsayilari){
                var splittedRakipSayi = rakipsayi.split('|');
                rakipsayilariDuz.add(splittedRakipSayi[0]);
              }
              print(myNumbers.decimals);
              return MaterialApp(
                home:Scaffold(
                  appBar: AppBar(
                    backgroundColor: Colors.amberAccent,
                    title: Text('Sayı Avı Oyun Ekranı'),
                  ),
                  body:Column(
                    children: <Widget>[
                      Expanded(
                        flex: 80,
                        child: Row(
                          children: <Widget>[
                            Expanded(
                              flex: 40,
                              child: Column(
                                children: <Widget>[
                                  for(var numbers in kullanicisayilariDuz)Text(numbers),
                                  ]
                              ),
                            ),
                            Expanded(
                              flex: 10,
                              child: Column(
                                  children: <Widget>[
                                    for(var numbers in sonuclarDuz)Text(numbers),
                                  ]
                              ),
                            ),
                            Expanded(
                              flex: 50,
                              child: Column(
                                children: <Widget>[
                                  for(var numbers in rakipsayilariDuz)Text(numbers),
                                ]
                              ),
                            ),
                          ],
                        ),
                      ),
                      Expanded(
                        flex:10,
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: <Widget>[
                            showDeleteNumbers(1,'numberimage1'),
                            showDeleteNumbers(2,'numberimage2'),
                            showDeleteNumbers(3,'numberimage3'),
                            showDeleteNumbers(4,'numberimage4'),
                            Expanded(
                              child:FlatButton(
                                onPressed: (){
                                  sendnumber();
                                },
                                child: Image.asset('images/send.png'),
                              ),
                            ),
                          ],
                        ),
                      ),
                      Expanded(
                        flex: 10,
                        child: Row(
                          children: <Widget>[
                            attachNumber('1','one.png'),
                            attachNumber('2','two.png'),
                            attachNumber('3','three.png'),
                            attachNumber('4','four.png'),
                            attachNumber('5','five.png'),
                            attachNumber('6','six.png'),
                            attachNumber('7','seven.png'),
                            attachNumber('8','eight.png'),
                            attachNumber('9','nine.png'),
                            attachNumber('0','zero.png'),
                          ],
                        ),
                      ),
                    ],
                  ),
                ),
              );
            }
          },
        );
      }
    }

提前致谢。

4

1 回答 1

1

The build function of your GameScreen needs to return a Widget:

Widget build(...) {}

However, when you display the dialogs, you do:

return _showMaterialDialog();

This dialogs function returns a Future<> which can not be a Widget. This explains the error.

I would prefer to declare them explicitly and they should return the dialogs inside the async function, as follows:

Future _showMaterialDialog() async {
    ...
    return showDialog(...);
}

By the way, using the same context passing into the parameter of the funtion should be better:

Future _showMaterialDialog(BuildContext context) {
    // use the local 'context' to build the dialog
}

Finally, in order to correctly use these dialogs, just show them and return at last a Widget:

if (...) {
    _showMaterialDialog(context);
}

return MaterialApp(...);

And, you don't need the two delayed you added, if you let the time of the UI to be displayed.
Indeed, because of using a StreamBuilder, the UI is not displayed yet, you need to wait when the main rendering pipeline has been flushed by using addPostFrameCallback:

WidgetsBinding.instance.addPostFrameCallback((_) {
    _showMaterialDialog(context);
}

PS: remember that Flutter is all Widgets, consider to refacto your code into small Widgets to avoid doing a lot of stuffs into one class only.

于 2020-11-04T23:20:04.713 回答