Есть ли обратный вызов, чтобы сообщить мне, когда в 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
}