Is there any callback to tell me when “build” func

2020-02-10 01:55发布

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
2条回答
家丑人穷心不美
2楼-- · 2020-02-10 02:41

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));
查看更多
爷的心禁止访问
3楼-- · 2020-02-10 02:57

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.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.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.

查看更多
登录 后发表回答