Search code examples
fluttertabsfuturesetstate

How to wait seState to be finished and widgets to be built before calling another function?


Hi StackOverFlow community, that's my first question here and I'm glad to be part of this community as it already helped me in plenty of things. I looked on this topic and didn't manage to find anything. I would like to redirect the DefaultTabController to the new tab created after waiting that it's loaded and built. I managed to find a workaround with the awaiting a Future.delayed wrapping setState but I don't think it's the best solution out there. When not using this FutureDelayed I get an error due to the fact that the button function is trying to redirect to a tab not yet crated as the DefaultTabController has not been yet rebuilt.

Function for adding a new tab inside a bottomSheet

Future<int> _addNewTab() async {
      await showModalBottomSheet(
...
...

IconButton(
                              onPressed: () {
                                final isValid =
                                    _formKey.currentState!.validate();
                                if (!isValid) {
                                  return;
                                }
                                Navigator.pop(context);
                                  setState(() {
                                    _tabs
                                        .add(_newTab.text);
                                  });
                                }
return _tabs.lenght-1;

Widget inside which I call the function

return DefaultTabController(
...
...

floatingActionButton: Padding(
                      //button to add a new tab
                      padding: const EdgeInsets.only(bottom: 25.0),
                      child: IconButton(
                        icon: Icon(
                          Icons.add_circle,
                          size: 55,
                        ),
                        onPressed: () async {
                          var page = await _addNewTab();
                          //awaiting this future delayed because we can't show a page which is not built yet
                          await Future.delayed(const Duration(milliseconds: 10),
                              () {
                            setState(() {});
                          });
                          //moving to the new tab built after awaiting it
                          if (mounted) { //checking that context is still alive and usable
                            DefaultTabController.of(context)!.animateTo(page);
                          }
                        },

Thanks a lot for your help in advance :)


Solution

  • yes, you have right, using the Future to wait for the 10 milliseconds fixes it but it's not the best solution.

    instead : first import the scheduler package, it's built-in in flutter, add this on top of your file :

    import 'flutter/scheduler.dart';
    

    then, replace this:

         await Future.delayed(const Duration(milliseconds: 10),
                () {
                  setState(() {});
                });
    

    with this:

    SchedulerBinding.instance.addPostFrameCallback(
      (_){
       setState(() {});
     })
    

    this will schedule the SetState(() {}) just one frame after it finishes executing all the code in that onPressed function, so the result will be an immediate SetState(() {}) after your page is on.