Show loading indicator /spinner when the page data isn't fully loaded from Firebase - Flutter

Viewed 583

In my Flutter app, I am using ModalProgressHUD to show a spinner when I click on save buttons in my form screens and it stops spinner once data successfully writes to Firebase.

I have this screen that uses Listview.builder to display a list of all my expenses and I want to automatically show spinner as soon as the page displays, and to stop spinner once all the data from Firebase fully loads.

I need assistance in doing this. I've pasted excerpt of my code as shown below. Thanks in advance.

//class wide declaration
bool showSpinner = true;



Widget build(BuildContext context) {

ExpenseNotifier expenseNotifier = Provider.of<ExpenseNotifier>(context);


Future<void> _resfreshList() async {
  expenseNotifier.getExpenses(expenseNotifier);
  var expenseList = ExpenseNotifier.getExpenses(expenseNotifier);
  if (expenseList != null) {
    setState(() {
      showSpinner = false;
    });
}

    return Scaffold(
      body: ModalProgressHUD(
            inAsyncCall: showSpinner,
            child: RefreshIndicator(
              onRefresh: _resfreshList,
              child: Consumer<ExpenseNotifier>(
                builder: (context, expense, child) {
                  return expense == null
                      ? Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          crossAxisAlignment: CrossAxisAlignment.center,
                          children: <Widget>[
                            PaddingClass(bodyImage: 'images/empty.png'),
                            SizedBox(
                              height: 20.0,
                            ),
                            Text(
                              'You don\'t have any expenses',
                              style: kLabelTextStyle,
                            ),
                          ],
                        )
                      : ListView.separated(
                          itemBuilder: (context, int index) {
                            var myExpense = expense.expenseList[index];
                            return Card(
                              elevation: 8.0,
                              color: Colors.white70,
                              child: Column(
                                mainAxisAlignment: MainAxisAlignment.start,
                                children: <Widget>[
                                  RegularExpenseTextPadding(
                                    regText:
                                        '${_formattedDate(myExpense.updatedAt)}',
                                  ),
                                  Container(
                                    margin: EdgeInsets.all(20.0),
                                    padding: const EdgeInsets.all(15.0),
                                    decoration: BoxDecoration(
                                      borderRadius:
                                          BorderRadius.all(Radius.circular(5.0)),
                                      border: Border.all(
                                          color: kThemeStyleBorderHighlightColour),
                                    ),
                                    child: Row(
                                      children: <Widget>[
                                        Expanded(
                                          flex: 5,
                                          child: Column(
                                            crossAxisAlignment:
                                                CrossAxisAlignment.start,
                                            children: <Widget>[
                                              Text(
                                                '${myExpense.amount}',
                                                style: kRegularTextStyle,
                                              ),
                                              SizedBox(
                                                height: 20.0,
                                              ),
                                              Text(
                                                myExpense.description,
                                                style: kRegularTextStyle,
                                              ),
                                            ],
                                          ),
                                        ),
                                        Expanded(
                                          flex: 1,
                                          child: GestureDetector(
                                            onTap: () {
                                              expenseNotifier.currentExpense =
                                                  expenseNotifier
                                                      .expenseList[index];
                                              Navigator.of(context).push(
                                                  MaterialPageRoute(builder:
                                                      (BuildContext context) {
                                                return ExpenseDetailsScreen();
                                              }));
                                            },
                                            child: Icon(
                                              FontAwesomeIcons.caretDown,
                                              color: kThemeIconColour,
                                            ),
                                          ),
                                        ),
                                      ],
                                    ),
                                  ),
                                ],
                              ),
                            );
                          },
                          separatorBuilder: (BuildContext context, int index) {
                            return SizedBox(
                              height: 20.0,
                            );
                          },
                          itemCount: expenseNotifier.expenseList.length,
                        );
                },
              ),
            ),
          ),
    );
    }
  
1 Answers

this is an example from my app:

bool _isLoading = false; <- default false
  bool _isInit = true; <- to mae it only load once


@override
  void initState() {

if (_isInit) {
     // activating spinner
      _isLoading = true;

      // your function here <------

    _isInit = false;
    super.initState();
  }

Initstate gets called before the user can see any kind of thin in your app, so this is the perfect place to make your firebase data load. with this logic from above the loading spinner shows as long you are receiving the data. And your body looks like the following then:

@override
  Widget build(BuildContext context) {

    return _isLoading <- is loading condition true? shows spinner
        ? Center(child: CircularProgressIndicator()) <- loading spinner
    // else shows your content of the app
    : SafeArea(
        child: Container()
            ....
Related