Is there any callback to tell me when "build" function is done in Flutter?

Flutter

Flutter Problem Overview


I have a listView in my screen. I have attached a controller to it. I am able to call my Endpoint, receive response, parse it and insert in row. ListView supposed to Scroll automatically. It does, but not in perfect way. I am always an item behind. This is my code:

@override
  Widget build(BuildContext context) {
    // Scroll to the most recent item
    if (equationList.length > 0) {
      _toEnd();
    }

    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: EquList(equationList, _scrollController),
      floatingActionButton: new FloatingActionButton(
        onPressed: onFabClick,
        tooltip: 'Fetch Post',
        child: new Icon(isLoading ? Icons.pause : Icons.play_arrow),
      ),
    );
  }

  void _toEnd() {
    _scrollController.animateTo(
      _scrollController.position.maxScrollExtent,
      duration: const Duration(milliseconds: 250),
      curve: Curves.ease,
    );
  }

The problem is, I am calling _toEnd() function before the last item inserts in to the list. So, I am looking for a callback (if there is any) that tells me build() is done. Then I call my _toEnd() function.

What is the best practice in this case?

Flutter Solutions


Solution 1 - Flutter

General solution

Just to clear things up, I did not expect this question to attract so much attention. Hence, I only answered for this very specific case.
As explained in another answer WidgetsBinding offers a way to add a one time post frame callback.

WidgetsBinding.instance!.addPostFrameCallback((_) {
  // executes after build
})

As this callback will only be called a single time, you will want to add it every time you build:

@override
Widget build(BuildContext context) {
  WidgetsBinding.instance!.addPostFrameCallback((_) => afterBuild);
  return Container(); // widget tree
}

void afterBuild() {
  // executes after build is done
}
Specific (async)

Elaborating on Günter's comment:

@override
Widget build(BuildContext context) {
  executeAfterBuild();
  return Container();
}

Future<void> executeAfterBuild() async {
  // this code will get executed after the build method
  // because of the way async functions are scheduled
}

There is a nice example illustrating that effect here.
Extensive information about scheduling in Dart can be found here.

Solution 2 - Flutter

The async way from @creativecreatorormaybenot is enough to answer the question for most situations.

But if you want to setState() or do something that will change widgets in the tree right after building the widget, you cannot use the async way. Because the callback will be fired during the build process of the widget tree. It will throw an exception :

Dart Error: Unhandled exception:
E/flutter (25259): setState() or markNeedsBuild() called during build.

For this situation, you can register a post frame callback to modify the widget:

@override
Widget build(BuildContext context) {
  WidgetsBinding.instance
    .addPostFrameCallback((_) => executeAfterWholeBuildProcess(context));

Solution 3 - Flutter

If you don't want to use WidgetsBinding:

  • Use Future or Timer (easy-peasy)
    @override
    Widget build(BuildContext context) {
      Future(_runsAfterBuild); // <-- This is all you need. 
      return Container();
    }
    
    Future<void> _runsAfterBuild() async {
      // This code runs after build ...
    }
    
  • Add a dummy wait (fixes @creativecreatureormaybenot problem)
    @override
    Widget build(BuildContext context) {
      _runsAfterBuild();
      return Container();
    }
      
    Future<void> _runsAfterBuild() async {
      await Future.delayed(Duration.zero); // <-- Add a 0 dummy waiting time
      // This code runs after build ...
    }
    

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHesamView Question on Stackoverflow
Solution 1 - FluttercreativecreatorormaybenotView Answer on Stackoverflow
Solution 2 - FlutterRockingDiceView Answer on Stackoverflow
Solution 3 - FlutterCopsOnRoadView Answer on Stackoverflow