'display loading indicator while list is being populating from an api

am new to flutter ... and am calling an api in my app and i want to display a loading indicator while the api function is finished and every thing is retrieved from the api .. how to achieve this?

class _CompaniesPageState extends State<CompaniesPage> {
  getcompanies() async {
  var url = 'my link';
  http
    .post(url, body: json.encode({ 'token': globals.token }))
    .then((response) {
      // print("Response body: ${response.body}");
      Map data = json.decode(response.body);
      final companies =
        (data['Companies'] as List).map((i) => new Company.fromJson(i));
      setState(() {
        for (final company in companies) {
          if (!company.category.contains("الراعي") &&
            !company.category.contains("الشريك") &&
            !company.category.contains("الداعم")) {
            if (company.logo != "") {
              names.add(company.name);
              logos.add(company.logo);
            }
          }
        }
      });
    });
}

@override
Widget build(BuildContext context) {
  getcompanies();
  if (globals.isguest) {
    return new Directionality(
      .....
    );
  }

}

List<Widget> createCompaniesChildren() {
  List<Widget> children = List<Widget>();
  for (int i = 0; i < names.length; i++) {
    children.add(
      new Padding(
        padding: new EdgeInsets.only(right: 15.0, left: 15.0),
        child: new Image.network(
          logos[i],
          width: 346.0,
          height: 180.0,
        ),
      ),
    );
    children.add(
      new Padding(
        padding: new EdgeInsets.only(right: 15.0, left: 15.0),
        child: new Center(
          child: new Text(
            names[i],
            style: new TextStyle(color: Colors.black, fontSize: 17.0),
            textAlign: TextAlign.center,
          ),
        ),
      ),
    );
    children.add(new Divider());
  }
  return children;
}

how can i display a loading indicator while the list is being populating and then dismiss it once it's finished??

Tried this:

          body: new Padding(
        padding: new EdgeInsets.only(top: 15.0),
        child: new Center(
          child: new FutureBuilder(
            future:
                getcompanies(), // your async method that returns a future
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              if (snapshot.hasData) {
                // if data is loaded
                if (snapshot.data != null) {
                  return new ListView.builder(
                    padding: new EdgeInsets.all(8.0),
                    itemExtent: 20.0,
                    itemBuilder: (BuildContext context, int i) {
                      return new Center(
                        child: new Text(
                          snapshot.data[i].name,
                          style: new TextStyle(
                              color: Colors.black, fontSize: 17.0),
                          textAlign: TextAlign.center,
                        ),
                      );
                    },
                  );
                } else {
                  // if data not loaded yet
                  return new CircularProgressIndicator();
                }
              }
            },
          ),
        ),
      ),

but got this error: I/flutter (31276): Another exception was thrown: A build function returned null.



Solution 1:[1]

You could use the FutureBuilder class for that purpose.

Also instead of manually creating the companies list you could use a ListView.

Something like this:

new FutureBuilder(
  future: getcompanies(), // your async method that returns a future
  builder: (BuildContext context, AsyncSnapshot snapshot) {
    if (snapshot.hasData) {
      // if data is loaded
      return new ListView.builder(
        padding: new EdgeInsets.all(8.0),
        itemExtent: 20.0,
        itemCount: snapshot.data.length,
        itemBuilder: (BuildContext context, int i) {
          return new Center(
            child: new Text(
              snapshot.data[i].name,
              style: new TextStyle(color: Colors.black, fontSize: 17.0),
              textAlign: TextAlign.center,
            ),
          );
        },
      ).build(context);
    } else {
      // if data not loaded yet
      return new CircularProgressIndicator();
    }
  },
)

Solution 2:[2]

Although you have already solved or got the answer. I will show you 2 Ways.

1. Using any builder like FutureBuilder, StreamBuilder....

FutureBuilder(
    future: getcompanies(), // your async method that returns a future
    builder: (context, snapshot) {
      switch (snapshot.connectionState) {
        case ConnectionState.active:

        case ConnectionState.waiting:
          return Padding(
            padding: const EdgeInsets.only(top: 20),
            child: Center(
                child: CircularProgressIndicator()
                ),
          );

        case ConnectionState.none:
          return Center(child: Text("Unable to connect right now"));

        case ConnectionState.done:
          if (snapshot.hasError) {
            print("Error: ${snapshot.error}");
          }

          return ListView.builder(
            scrollDirection: Axis.horizontal,
            itemCount: snapshot.data!.length,
            itemBuilder: (BuildContext context, int i) {
              return new Center(
                child: new Text(
                  snapshot.data[i].name,
                  style: new TextStyle(color: Colors.black, fontSize: 17.0),
                  textAlign: TextAlign.center,
                ),
              );
            },
          );
      }
    },
  ),

2. Without using builder

Put this code before API call, Like

AlertDialog alert = AlertDialog(
      content: Row(children: [
        CircularProgressIndicator(
          backgroundColor: Colors.red,
        ),
        Container(margin: EdgeInsets.only(left: 10), child: Text("Loading...")),
      ]),
    );
    showDialog(
      barrierDismissible: false,
      context: context,
      builder: (BuildContext context) {
        return alert;
      },
    );
api.getcompanies();

And after getting API response

var response = api.getcompanies();
Navigator.pop(context);

Note : You can put the code into a method and then call it here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2