0

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 :)

salim.elkh
  • 11
  • 3

2 Answers2

1

Thanks to Gwhyyy I discovered about SchedulerBinding. Here a link with a similar question already answered with different solutions hoping it helps.

Flutter: Run method on Widget build complete

Have a good day!

salim.elkh
  • 11
  • 3
0

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.

Gwhyyy
  • 7,554
  • 3
  • 8
  • 35
  • Thanks a lot mate! I checked with this solution but it didn't work, so I tried to wrap the DefaultTabController.of(context)!.animateTo(page) with the schedulerBinding code you provided and works fine :) Thanks again and have a great day :) – salim.elkh Nov 07 '22 at 05:45