Search code examples
androidflutterdartwidgetflutter-futurebuilder

Future<Widget> can't be assigned to the list type 'widget'


I'm making a dialog screen which contains a dropbox and list view like below.

showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            content: StatefulBuilder(
              builder: (BuildContext DialogContext, StateSetter setState) {
                return Column(
                  children: [
                    Dropdown(DialogContext, setState, 0, ReceiveArgs, _lListOfDepthList), 
                    Dropdown(DialogContext, setState, 1, ReceiveArgs, _lListOfDepthList),                        
                    FutureListView(ReceiveArgs),                                            
                  ],
                );
              },
            ),
          );
        });

Since I called SetName, which returns a Future, I needed to change 'FutureListView' to a Future function too.

  Future<Widget> FutureListView(ArgumentClass ReceiveArgs) async{
    String SelectedFullAddress = GetSelectedAddress(5, "");

    _Name = await SetName(ReceiveArgs.lFullList, SelectedFullAddress);

    if (_Name.isNotEmpty) {
      print("ListView!");
      return ListView.builder(
        itemCount: _Name.length,
        itemBuilder: (context, index) {
          return CheckboxListTile(
            title: Text(_Name[index]),
            value: null,
            onChanged: null,
          );
        },
      );
    } else {
      print("List Null");
      return Text("");
    }
  }

However after the change, I get this error at compile time:

error: The element type 'Future' can't be assigned to the list type 'Widget'. (list_element_type_not_assignable at [checker_v2])

How do I provide a Future to the List which expects only Widgets?


Solution

  • Use a FutureBuilder.

    Here's how your FutureListView should look like (you can change the name of the method now)

     Future<String> FutureListView(ArgumentClass ReceiveArgs) async{
            String SelectedFullAddress = GetSelectedAddress(5, "");
      
            return await SetName(ReceiveArgs.lFullList, SelectedFullAddress);
          }
    

    And, this should be your showDialog

    showDialog(
            context: context,
            builder: (BuildContext context) {
              return AlertDialog(
                content: StatefulBuilder(
                  builder: (BuildContext DialogContext, StateSetter setState) {
                    return Column(
                      children: [
                        Dropdown(DialogContext, setState, 0, ReceiveArgs, _lListOfDepthList),
                        Dropdown(DialogContext, setState, 1, ReceiveArgs, _lListOfDepthList),
                        FutureBuilder<String>(
                        future: FutureListView(ReceiveArgs),
                        builder: (context, snapshot) => {
                          if(!snapshot.hasData) return Container(); // This container can be a loading screen, since its waiting for data.
    
                          if(snapshot.data.isNotEmpty){
                            print("ListView!");
                            return ListView.builder(
                              itemCount: _Name.length,
                              itemBuilder: (context, index) {
                                return CheckboxListTile(
                                  title: Text(_Name[index]),
                                  value: null,
                                  onChanged: null,
                                  );
                                },
                              );,
                            } else {
                              print("List Null");
                              return Text("");
                          },
                        )
                      ],
                    );
                  },
                ),
              );
            });
    

    FutureBuilder's future won't wait until the async method is completed, but try to build the builder method until it is. You can use snapshot.hasData to check if the async method has returned something already, and if it doesn't, you can show a loading screen if you want. Then, use snapshot.data to access the result of your future.