Тип флаттера ‘Future’ не является подтипом ошибки типа ‘Widget’

#flutter #flutter-alertdialog

#флаттер #flutter-alertdialog

Вопрос:

Я добавил всплывающее окно (alertdialog) в свой проект flutter, в котором есть streambuilder. Сначала это не сработало, но после создания его асинхронным и добавления кода, подобного приведенному ниже

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

Он начал работать нормально. Это всплывающее окно будет возникать после определенных изменений данных в базе данных. Позже я захотел добавить в свой проект второе всплывающее окно для второго значения базы данных, разница в том, что у этого есть текстовое поле для ввода пользователем и, конечно, контроллер для этого. Когда я попробовал это всплывающее окно, оно работало нормально, но в конце всплывающего окна оно выдавало

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

ошибка с красным / желтым фоном ошибки. Разница между этими 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 gameResu<
      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'),
                          ],
                        ),
                      ),
                    ],
                  ),
                ),
              );
            }
          },
        );
      }
    }
  

Заранее спасибо.

Ответ №1:

build Ваша функция GameScreen должна возвращать Widget :

 Widget build(...) {}
  

Однако при отображении диалоговых окон вы:

 return _showMaterialDialog();
  

Эта диалоговая функция возвращает a Future<> , который не может быть виджетом. Это объясняет ошибку.

Я бы предпочел объявить их явно, и они должны возвращать диалоги внутри асинхронной функции следующим образом:

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

Кстати, использование того же контекста, передаваемого в параметр функции, должно быть лучше:

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

Наконец, чтобы правильно использовать эти диалоговые окна, просто покажите их и верните, наконец, виджет:

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

return MaterialApp(...);
  

И вам не нужны те два delayed , которые вы добавили, если вы разрешите отображать время пользовательского интерфейса.
Действительно, из-за использования a StreamBuilder пользовательский интерфейс еще не отображается, вам нужно дождаться, когда основной конвейер рендеринга будет сброшен с помощью addPostFrameCallback :

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

PS: помните, что Flutter — это все виджеты, подумайте о том, чтобы преобразовать ваш код в небольшие виджеты, чтобы не делать много вещей только в одном классе.

Комментарии:

1. Спасибо за ответ, это сработало, но устранение двух задержек, вызывающих проблемы. Я не знаю почему.

2. @Faruk Я думаю, это из-за рендеринга StreamBuilder. Я отредактировал свой ответ, чтобы включить эту часть, вы должны попробовать и дать мне знать.