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

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

我在我的 flutter 项目中添加了一个弹出窗口 window (alertdialog),它有一个 streambuilder。一开始它不起作用,但在使其异步并添加如下代码后

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

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

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

错误背景为 red/yellow。这 2 个弹出窗口之间的区别正如我所说,其中一个具有输入控制器,我在这里做错了什么?

完整代码如下:

   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'),
                          ],
                        ),
                      ),
                    ],
                  ),
                ),
              );
            }
          },
        );
      }
    }

提前致谢。

你的GameScreenbuild函数需要return一个Widget:

Widget build(...) {}

但是,当您显示对话框时,您会:

return _showMaterialDialog();

此对话框函数 return 是一个 Future<>,不能是 Widget。这解释了错误。

我更愿意显式地声明它们,它们应该return异步函数中的对话框,如下所示:

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

顺便说一句,使用相同的上下文传递给函数的参数应该更好:

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

最后,为了正确使用这些对话框,只需显示它们,return最后一个小部件:

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

return MaterialApp(...);

而且,如果你让 UI 的时间显示出来,你不需要你添加的两个 delayed
事实上,由于使用了StreamBuilder,UI还没有显示,你需要等待主渲染管道被使用addPostFrameCallback:

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

PS:记住 Flutter 都是 Widget,考虑将您的代码重构为小 Widget,以避免将很多东西做成一个 class。