【问题标题】:Is there any callback to tell me when "build" function is done in Flutter?在 Flutter 中完成“构建”功能时是否有任何回调告诉我?
【发布时间】:2018-12-15 10:04:53
【问题描述】:

我的屏幕上有一个 listView。我已将控制器连接到它。我可以调用我的端点,接收响应,解析它并插入行。 ListView 应该自动滚动。确实如此,但不是以完美的方式。我总是落后。这是我的代码:

@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,
    );
  }

问题是,我在最后一项插入列表之前调用了_toEnd() 函数。所以,我正在寻找一个回调(如果有的话)告诉我build() 已经完成。然后我调用我的_toEnd() 函数。

在这种情况下,最佳做法是什么?

【问题讨论】:

  • 请注意,我们更喜欢这里的技术写作风格。我们轻轻地劝阻问候,希望你能帮助,谢谢,提前感谢,感谢信,问候,亲切的问候,签名,请你能帮助,聊天材料和缩写 txtspk,恳求,你多久了被卡住、投票建议、元评论等。只需解释您的问题,并展示您尝试过的内容、预期的内容以及实际发生的情况。
  • 更好的方法是在ListView 中设置reverse: true 或滚动视图(如果您使用一个并以相反的顺序传递内容)。
  • @GünterZöchbauer,我正在这样做。但问题是,我仍然需要一个回调来告诉我构建完成。
  • 你需要它做什么? build() 是同步的,所以如果你在 build() 中执行异步操作,它将在 build() 完成后执行。
  • 谢谢@GünterZöchbauer,您可以举个例子回答您的建议吗?我是 Flutter 的新手,恐怕我没有让你好起来。谢谢。

标签: flutter


【解决方案1】:

一般解决方案

只是为了澄清一下,我没想到这个问题会引起如此多的关注。因此,我只回答了这个非常具体的案例。
正如explained in another answer WidgetsBinding 提供了一种添加一次性 后帧回调的方法。

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

由于此回调将only be called a single time,因此您需要在每次构建时添加它:

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

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

特定(异步)

详述Günter's评论:

@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
}

有一个很好的例子illustrating that effect here
关于Dart 中调度的详细信息can be found here

【讨论】:

  • 我不知道同步功能完成后会运行异步。它像魅力一样工作。感谢您的示例代码。
  • @creativecreatorormaybenot 我不认为仅仅通过将函数标记为异步(使用async 关键字),其中的代码将被安排在事件队列中。您应该使用Future(() {}) 或它的其他构造函数形式。
  • 异步函数内部的代码不能是任意随机代码。我们必须确保我们返回一个 Future 对象,然后编写我们想要实际执行的代码。例如: Future executeAfterBuild() async {await Future.delayed(Duration(milliseconds:10)); )// 要执行的代码 }.当这个 async 函数被调用时,我们会得到一个未完成状态的 Future 对象,因为我们调用了这个 async 函数而不做 await。
【解决方案2】:

@creativecreatorormaybenot 的异步方式足以回答大多数情况下的问题。

但如果你想setState() 或在构建小部件后立即更改树中的小部件,则不能使用异步方式。因为回调将在小部件树的构建过程中触发。它会抛出一个异常:

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

对于这种情况,你可以注册一个post frame回调来修改widget:

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

【讨论】:

  • 接受的答案错过了作为参数的“上下文”。因为它对我来说不能正常工作
猜你喜欢
  • 2020-06-18
  • 1970-01-01
  • 1970-01-01
  • 2015-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多