Flutter类型'Future <dynamic>'不是'Widget'类型错误的子类型

问题描述

我在具有流构建器的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'),);
            }
          },);
      }
    }

谢谢。

解决方法

您的build的{​​{1}}函数需要返回一个GameScreen

Widget

但是,当您显示对话框时,您可以这样做:

Widget build(...) {}

此对话框函数返回一个return _showMaterialDialog(); ,它不能是窗口小部件。这说明了错误。

我希望显式声明它们,并且它们应该在异步函数内部返回对话框,如下所示:

Future<>

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

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

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

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

而且,如果您要显示UI的时间,则不需要添加两个if (...) { _showMaterialDialog(context); } return MaterialApp(...);
确实,由于使用delayed,因此尚未显示UI,您需要等待使用StreamBuilder刷新主渲染管道后:

addPostFrameCallback

PS:请记住,Flutter都是小部件,请考虑将您的代码重新编译为小部件,以避免只在一个类中做很多事情。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...