Есть ли обратный вызов, чтобы сообщить мне, когда в Flutter выполняется функция "build"?

У меня есть 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() функция.

Какова лучшая практика в этом случае?

4 ответа

Решение

Разработка комментария Günter Zöchbauer:

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

Вот хороший пример, иллюстрирующий этот эффект.
Обширная информация о планировании в Dart может быть найдена здесь.

creativecreatorormaybenot пути от creativecreatorormaybenot достаточно, чтобы ответить на вопрос для большинства ситуаций.

Но если вы хотите setState() или сделать что-то, что изменит виджеты в дереве сразу после сборки виджета, вы не можете использовать асинхронный способ. Потому что обратный вызов будет запущен в процессе сборки дерева виджетов. Это выдаст исключение:

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

В этой ситуации вы можете зарегистрировать обратный вызов после фрейма, чтобы изменить виджет:

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

Если вы не хотите использовать WidgetsBinding:

  • Использовать Futureили же Timer(очень просто)

            @override
    Widget build(BuildContext context) {
      Future(_runsAfterBuild); // <-- This is all you need. 
      return Container();
    }
    
    Future<void> _runsAfterBuild() async {
      // This code runs after build ...
    }
    
  • Добавить фиктивное ожидание (исправляет проблему @creativecreatureormaybenot )

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

Использование Future.delayed позволит лучше убедиться, что код выполняется после сборки.

@override
Widget build(BuildContext context) {
  Future.delayed(Duration.zero, () => executeAfterBuild());
  return Container();
}

Future<void> executeAfterBuild() async {
  // this code will get executed after the build method
}
Другие вопросы по тегам